Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ jobs:
include:
- build: pinned
os: ubuntu-latest
rust: 1.60.0
rust: 1.71.0
- build: pinned-win
os: windows-latest
rust: 1.60.0
rust: 1.71.0
- build: stable
os: ubuntu-latest
rust: stable
Expand Down
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,5 @@ examples/ss10pusa.csv
build
target
Cargo.lock
scratch*
bench_large/huge
tmp
23 changes: 22 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ categories = ["filesystem"]
license = "Unlicense/MIT"
exclude = ["/ci/*", "/.travis.yml", "/appveyor.yml"]
edition = "2018"
rust-version = "1.71"

[badges]
travis-ci = { repository = "BurntSushi/walkdir" }
Expand All @@ -23,8 +24,28 @@ members = ["walkdir-list"]
[dependencies]
same-file = "1.0.1"

[target.'cfg(unix)'.dependencies.libc]
version = "0.2.186"

[build-dependencies]
cc = "1.0.36"

[target.'cfg(windows)'.dependencies.windows-sys]
version = "0.61"
features = [
"Wdk_Foundation",
"Wdk_Storage_FileSystem",
"Win32_Foundation",
"Win32_Security",
"Win32_Storage_FileSystem",
"Win32_System_IO",
]

[target.'cfg(windows)'.dependencies.winapi-util]
version = "0.1.1"
version = "0.1.11"

[dev-dependencies]
doc-comment = "0.3"

[profile.release]
debug = true
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ for entry in walker.filter_entry(|e| !is_hidden(e)) {

### Minimum Rust version policy

This crate's minimum supported `rustc` version is `1.60.0`.
This crate's minimum supported `rustc` version is `1.71.0`.

The current policy is that the minimum Rust version required to use this crate
can be increased in minor version updates. For example, if `crate 1.0` requires
Expand Down
58 changes: 58 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
fn main() {
if check_cfg_supported() {
println!("cargo:rustc-check-cfg=cfg(walkdir_getdents)");
println!("cargo:rustc-check-cfg=cfg(walkdir_unix)");
}

let target_os = match std::env::var_os("CARGO_CFG_TARGET_OS") {
Some(target_os) => target_os,
None => return,
};
let target_os = target_os.to_string_lossy();
if supports_unix_backend(&target_os) {
println!("cargo:rustc-cfg=walkdir_unix");
}
if target_os == "dragonfly" {
cc::Build::new()
.file("src/os/unix/errno-dragonfly.c")
.compile("errno-dragonfly");
}
if target_os == "linux"
&& std::env::var_os("CARGO_CFG_WALKDIR_DISABLE_GETDENTS").is_none()
{
println!("cargo:rustc-cfg=walkdir_getdents");
}
}

fn check_cfg_supported() -> bool {
let rustc = std::env::var_os("RUSTC").unwrap_or_else(|| "rustc".into());
let output =
match std::process::Command::new(rustc).arg("--version").output() {
Ok(output) => output,
Err(_) => return false,
};
let version = String::from_utf8_lossy(&output.stdout);
let minor = version
.split_whitespace()
.nth(1)
.and_then(|version| version.split('.').nth(1))
.and_then(|minor| minor.parse::<u32>().ok());
matches!(minor, Some(minor) if minor >= 80)
}

fn supports_unix_backend(target_os: &str) -> bool {
matches!(
target_os,
"android"
| "dragonfly"
| "emscripten"
| "freebsd"
| "fuchsia"
| "haiku"
| "linux"
| "macos"
| "netbsd"
| "openbsd"
| "solaris"
)
}
126 changes: 75 additions & 51 deletions src/dent.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use std::ffi::OsStr;
use std::fmt;
use std::fs::{self, FileType};
use std::fs;
use std::path::{Path, PathBuf};

use crate::error::Error;
use crate::Result;
use crate::{FileType, Result};

/// A directory entry.
///
Expand Down Expand Up @@ -48,14 +48,6 @@ pub struct DirEntry {
/// The underlying inode number (Unix only).
#[cfg(unix)]
ino: u64,
/// The underlying metadata (Windows only). We store this on Windows
/// because this comes for free while reading a directory.
///
/// We use this to determine whether an entry is a directory or not, which
/// works around a bug in Rust's standard library:
/// https://github.com/rust-lang/rust/issues/46484
#[cfg(windows)]
metadata: fs::Metadata,
}

impl DirEntry {
Expand Down Expand Up @@ -124,21 +116,6 @@ impl DirEntry {
/// [`std::fs::metadata`]: https://doc.rust-lang.org/std/fs/fn.metadata.html
/// [`std::fs::symlink_metadata`]: https://doc.rust-lang.org/stable/std/fs/fn.symlink_metadata.html
pub fn metadata(&self) -> Result<fs::Metadata> {
self.metadata_internal()
}

#[cfg(windows)]
fn metadata_internal(&self) -> Result<fs::Metadata> {
if self.follow_link {
fs::metadata(&self.path)
} else {
Ok(self.metadata.clone())
}
.map_err(|err| Error::from_entry(self, err))
}

#[cfg(not(windows))]
fn metadata_internal(&self) -> Result<fs::Metadata> {
if self.follow_link {
fs::metadata(&self.path)
} else {
Expand All @@ -155,7 +132,7 @@ impl DirEntry {
/// This never makes any system calls.
///
/// [`follow_links`]: struct.WalkDir.html#method.follow_links
pub fn file_type(&self) -> fs::FileType {
pub fn file_type(&self) -> FileType {
self.ty
}

Expand All @@ -182,21 +159,45 @@ impl DirEntry {
}

#[cfg(windows)]
pub(crate) fn from_entry(
pub(crate) fn from_os_entry(
depth: usize,
ent: &fs::DirEntry,
parent_path: &Path,
ent: &crate::os::windows::DirEntry,
) -> Result<DirEntry> {
let path = ent.path();
let ty = ent
.file_type()
.map_err(|err| Error::from_path(depth, path.clone(), err))?;
let md = ent
.metadata()
.map_err(|err| Error::from_path(depth, path.clone(), err))?;
Ok(DirEntry { path, ty, follow_link: false, depth, metadata: md })
let path = parent_path.join(ent.file_name_os());
Ok(DirEntry {
path,
ty: ent.file_type().into(),
follow_link: false,
depth,
})
}

#[cfg(unix)]
#[cfg(walkdir_unix)]
pub(crate) fn from_os_entry(
depth: usize,
parent_path: &Path,
parent_fd: Option<std::os::unix::io::RawFd>,
ent: &crate::os::unix::DirEntry,
) -> Result<DirEntry> {
let path = parent_path.join(ent.file_name_os());
let ty = match ent.file_type() {
Some(file_type) => file_type.into(),
None => {
let metadata = match parent_fd {
Some(fd) => {
crate::os::unix::lstatat_c(fd, ent.file_name())
}
None => crate::os::unix::lstat(path.clone()),
}
.map_err(|err| Error::from_path(depth, path.clone(), err))?;
metadata.file_type().into()
}
};
Ok(DirEntry { path, ty, follow_link: false, depth, ino: ent.ino() })
}

#[cfg(all(unix, not(walkdir_unix)))]
pub(crate) fn from_entry(
depth: usize,
ent: &fs::DirEntry,
Expand All @@ -208,7 +209,7 @@ impl DirEntry {
.map_err(|err| Error::from_path(depth, ent.path(), err))?;
Ok(DirEntry {
path: ent.path(),
ty,
ty: ty.into(),
follow_link: false,
depth,
ino: ent.ino(),
Expand All @@ -223,7 +224,12 @@ impl DirEntry {
let ty = ent
.file_type()
.map_err(|err| Error::from_path(depth, ent.path(), err))?;
Ok(DirEntry { path: ent.path(), ty, follow_link: false, depth })
Ok(DirEntry {
path: ent.path(),
ty: ty.into(),
follow_link: false,
depth,
})
}

#[cfg(windows)]
Expand All @@ -232,23 +238,42 @@ impl DirEntry {
pb: PathBuf,
follow: bool,
) -> Result<DirEntry> {
let md = if follow {
fs::metadata(&pb)
.map_err(|err| Error::from_path(depth, pb.clone(), err))?
let metadata = if follow {
crate::os::windows::stat(&pb)
} else {
fs::symlink_metadata(&pb)
.map_err(|err| Error::from_path(depth, pb.clone(), err))?
};
crate::os::windows::lstat(&pb)
}
.map_err(|err| Error::from_path(depth, pb.clone(), err))?;
Ok(DirEntry {
path: pb,
ty: md.file_type(),
ty: metadata.file_type().into(),
follow_link: follow,
depth,
metadata: md,
})
}

#[cfg(unix)]
#[cfg(walkdir_unix)]
pub(crate) fn from_path(
depth: usize,
pb: PathBuf,
follow: bool,
) -> Result<DirEntry> {
let metadata = if follow {
crate::os::unix::stat(pb.clone())
} else {
crate::os::unix::lstat(pb.clone())
}
.map_err(|err| Error::from_path(depth, pb.clone(), err))?;
Ok(DirEntry {
path: pb,
ty: metadata.file_type().into(),
follow_link: follow,
depth,
ino: metadata.ino(),
})
}

#[cfg(all(unix, not(walkdir_unix)))]
pub(crate) fn from_path(
depth: usize,
pb: PathBuf,
Expand All @@ -265,7 +290,7 @@ impl DirEntry {
};
Ok(DirEntry {
path: pb,
ty: md.file_type(),
ty: md.file_type().into(),
follow_link: follow,
depth,
ino: md.ino(),
Expand All @@ -287,7 +312,7 @@ impl DirEntry {
};
Ok(DirEntry {
path: pb,
ty: md.file_type(),
ty: md.file_type().into(),
follow_link: follow,
depth,
})
Expand All @@ -302,7 +327,6 @@ impl Clone for DirEntry {
ty: self.ty,
follow_link: self.follow_link,
depth: self.depth,
metadata: self.metadata.clone(),
}
}

Expand Down
Loading
Loading