dirwalk 1.1.1

Platform-optimized recursive directory walker with metadata
Documentation
use crate::entry::Entry;
use crate::error::Error;
use crate::walk::StorageHint;
use std::os::unix::fs::MetadataExt;
use std::path::Path;

pub(super) fn build_relative_path(prefix: &str, name: &str) -> String {
    if prefix.is_empty() {
        name.to_owned()
    } else {
        let mut s = String::with_capacity(prefix.len() + 1 + name.len());
        s.push_str(prefix);
        s.push(std::path::MAIN_SEPARATOR);
        s.push_str(name);
        s
    }
}

pub fn scan_dir_platform(
    path: &Path,
    prefix: &str,
    _hint: StorageHint,
) -> Result<Vec<Entry>, Error> {
    let mut entries = Vec::with_capacity(32);
    let mut child_path = path.to_path_buf();

    for result in std::fs::read_dir(path).map_err(|e| Error::Io {
        path: path.to_path_buf(),
        source: e,
    })? {
        let dir_entry = match result {
            Ok(e) => e,
            Err(_) => continue,
        };

        let raw_name = dir_entry.file_name();
        let name_str = raw_name.to_string_lossy();

        child_path.push(name_str.as_ref());
        let meta = match std::fs::symlink_metadata(&child_path) {
            Ok(m) => m,
            Err(_) => {
                child_path.pop();
                continue;
            }
        };
        child_path.pop();

        let is_symlink = meta.file_type().is_symlink();
        let is_dir = meta.is_dir();
        let is_hidden = name_str.starts_with('.');

        // Build relative_path last so name_str can be used above without cloning.
        let relative_path = build_relative_path(prefix, &name_str);

        let modified = meta.mtime();

        let size = if is_symlink { 0 } else { meta.len() };

        entries.push(Entry {
            relative_path,
            depth: 0,
            size,
            is_dir,
            is_symlink,
            is_hidden,
            modified,
        });
    }

    Ok(entries)
}