-
-
Notifications
You must be signed in to change notification settings - Fork 125
Follows macOS/APFS "firmlinks" even with .follow_links(false) #169
Description
macOS with APFS has a feature called "firmlinks" which are sometimes described as being between hardlinks and symlinks. They're used to make two system partitions appear like the old single partition scheme. Certain directories that live in /System/Volumes/Data/xyz are firmlinked to /xyz
Swift's standard library is aware of these and its dir walking functionality does not follow them. Rust's walkdir is not aware of them and does follow them. (Note that there's no commandline switches for mac's ls that reveal them)
I wrote similar code for both Swift and Rust. It's probably not the best, I'm just learning both languages. First argument is path the walk begins, second is a substring to match in the name of a directory to cause it to be printed out.
Rust: cargo run / LLVM
/Library/Frameworks/Xamarin.iOS.framework/Versions/15.10.0.5/LLVM
/System/Volumes/Data/Library/Frameworks/Xamarin.iOS.framework/Versions/15.10.0.5/LLVM
/System/Volumes/Data/Users/hippietrail/.vscode-insiders/extensions/ms-vscode.cpptools-1.5.1/LLVM
/System/Volumes/Data/Users/hippietrail/.vscode/extensions/ms-vscode.cpptools-1.12.4-darwin-arm64/LLVM
/System/Volumes/Data/Applications/Xcode.app/Contents/Applications/Instruments.app/Contents/PlugIns/DTLLVMBinaryAnalysisPlugin.xrplugin
/Users/hippietrail/.vscode-insiders/extensions/ms-vscode.cpptools-1.5.1/LLVM
/Users/hippietrail/.vscode/extensions/ms-vscode.cpptools-1.12.4-darwin-arm64/LLVM
/Applications/Xcode.app/Contents/Applications/Instruments.app/Contents/PlugIns/DTLLVMBinaryAnalysisPlugin.xrplugin
done
Swift: dirwalker / LLVM
Library/Frameworks/Xamarin.iOS.framework/Versions/15.10.0.5/LLVM
Users/hippietrail/.vscode-insiders/extensions/ms-vscode.cpptools-1.5.1/LLVM
Users/hippietrail/.vscode/extensions/ms-vscode.cpptools-1.12.4-darwin-arm64/LLVM
Applications/Xcode.app/Contents/Applications/Instruments.app/Contents/PlugIns/DTLLVMBinaryAnalysisPlugin.xrplugin
done
Rust code:
use std::env;
use walkdir::WalkDir;
fn main() {
let args: Vec<String> = env::args().collect();
let path: &str = args[1].as_str();
let text: &str = args[2].as_str();
if args.len() == 3 {
for entry in WalkDir::new(path).follow_links(false)
.into_iter()
.filter_map(|e| e.ok())
.filter(|e| e.file_type().is_dir())
.filter(|e| e.file_name().to_str().unwrap().contains(text)) {
println!("{}", entry.path().display());
}
println!("done");
} else {
println!("** usage: first arg is start directory, second is substring to look for in directory paths");
}
}Swift code:
import Foundation
import AppKit
let fileManager = FileManager.default
let resKeys : [URLResourceKey] = [.isDirectoryKey, .fileSizeKey, .isSymbolicLinkKey]
let startURL: URL = URL(string: fileManager.currentDirectoryPath)!
guard CommandLine.arguments.count == 3 else {
print("** usage: dirwalker path string")
exit(1);
}
let pathArg = CommandLine.arguments[1]
let matchArg = CommandLine.arguments[2]
if let path = pathArg.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) {
if let url = URL(string: path) {
let en = fileManager.enumerator(at: url,
includingPropertiesForKeys: resKeys,
options: [.producesRelativePathURLs],
errorHandler: { (url, error) -> Bool in
return true }
)!
mainloop: for case let fileURL as URL in en {
do {
let rv = try fileURL.resourceValues(forKeys: Set(resKeys))
if let d = rv.isDirectory, d {
let filename: String = fileURL.lastPathComponent;
if filename.contains(matchArg) {
print(fileURL.relativePath)
}
}
} catch {
print("** error 2:", error)
}
}
}
}
print("done")