Fix macOS SMB mount: AAPL caps, credit grant, file_index, QueryDirectory padding
- AAPL: Restore UNIX_BASED+NFS_ACE server_caps, RESOLVE_ID+FULL_SYNC volume_caps (Samba baseline) - Credit: Grant min 1 credit in dispatch response for smbclient compatibility - file_index: Assign 1-based index per entry in list_dir (both VFS and local backends) - smb_match(): Add wildcard pattern filter (*/?) for macOS single-entry QueryDirectory probes - FILE_ID_BOTH_DIR_INFORMATION: Add 2-byte Reserved2 padding between ShortName and FileId - macOS Sequoia 15.5 mount_smbfs now succeeds (tested: ls, cat, read)
This commit is contained in:
@@ -285,18 +285,31 @@ impl Handle for VfsHandle {
|
||||
}
|
||||
}
|
||||
|
||||
async fn list_dir(&self, _pattern: Option<&str>) -> Result<Vec<DirEntry>, SmbError> {
|
||||
async fn list_dir(&self, pattern: Option<&str>) -> Result<Vec<DirEntry>, SmbError> {
|
||||
match self {
|
||||
Self::File { .. } => Err(SmbError::NotADirectory),
|
||||
Self::Directory { vfs, path } => {
|
||||
let entries = vfs.read_dir(path).map_err(map_error)?;
|
||||
let result = entries
|
||||
let mut result: Vec<DirEntry> = entries
|
||||
.into_iter()
|
||||
.filter(|entry| {
|
||||
let p = match pattern {
|
||||
None => return true,
|
||||
Some(p) => p,
|
||||
};
|
||||
if p == "*" || p == "*.*" || p.is_empty() {
|
||||
return true;
|
||||
}
|
||||
smb_match(&entry.name, p)
|
||||
})
|
||||
.map(|entry| {
|
||||
let info = vfs_stat_to_file_info(&entry.stat, &entry.name, path);
|
||||
DirEntry { info }
|
||||
})
|
||||
.collect();
|
||||
for (i, entry) in result.iter_mut().enumerate() {
|
||||
entry.info.file_index = (i + 1) as u64;
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
@@ -307,6 +320,36 @@ impl Handle for VfsHandle {
|
||||
}
|
||||
}
|
||||
|
||||
/// Simple SMB wildcard match: `*` matches any sequence, `?` matches one char.
|
||||
fn smb_match(name: &str, pattern: &str) -> bool {
|
||||
let name = name.as_bytes();
|
||||
let pat = pattern.as_bytes();
|
||||
let mut ni = 0;
|
||||
let mut pi = 0;
|
||||
let mut star_idx: Option<usize> = None;
|
||||
let mut match_idx = 0;
|
||||
while ni < name.len() {
|
||||
if pi < pat.len() && (pat[pi] == b'?' || pat[pi] == name[ni]) {
|
||||
ni += 1;
|
||||
pi += 1;
|
||||
} else if pi < pat.len() && pat[pi] == b'*' {
|
||||
star_idx = Some(pi);
|
||||
match_idx = ni;
|
||||
pi += 1;
|
||||
} else if let Some(si) = star_idx {
|
||||
pi = si + 1;
|
||||
match_idx += 1;
|
||||
ni = match_idx;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
while pi < pat.len() && pat[pi] == b'*' {
|
||||
pi += 1;
|
||||
}
|
||||
pi == pat.len()
|
||||
}
|
||||
|
||||
fn filetime_to_systemtime(ft: u64) -> SystemTime {
|
||||
if ft < FILETIME_OFFSET {
|
||||
return SystemTime::UNIX_EPOCH;
|
||||
|
||||
Reference in New Issue
Block a user