-
Notifications
You must be signed in to change notification settings - Fork 32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
file.find() #405
file.find() #405
Changes from all commits
7e33e6b
43c686a
80def3d
23c562e
b29c6c6
0094640
e9bed88
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
use std::{path::{Path, PathBuf}, time::{SystemTime, UNIX_EPOCH}}; | ||
use anyhow::{anyhow, Result}; | ||
use std::fs::canonicalize; | ||
#[cfg(unix)] | ||
use std::os::unix::fs::PermissionsExt; | ||
|
||
fn check_path(path: &PathBuf, name: Option<String>, file_type: Option<String>, permissions: Option<u64>, modified_time: Option<u64>, create_time: Option<u64>) -> Result<bool> { | ||
if let Some(name) = name { | ||
if !path.file_name().ok_or(anyhow!("Failed to get item file name"))?.to_str().ok_or(anyhow!("Failed to convert file name to str"))?.contains(&name) { | ||
return Ok(false); | ||
} | ||
} | ||
if let Some(file_type) = file_type { | ||
if !path.is_file() && file_type == "file" { | ||
return Ok(false); | ||
} | ||
if !path.is_dir() && file_type == "dir" { | ||
return Ok(false); | ||
} | ||
} | ||
if let Some(permissions) = permissions { | ||
let metadata = path.metadata()?.permissions(); | ||
#[cfg(unix)] | ||
{ | ||
if metadata.mode() != (permissions as u32) { | ||
return Ok(false); | ||
} | ||
} | ||
#[cfg(windows)] | ||
{ | ||
if permissions == 0 && metadata.readonly() { | ||
return Ok(false); | ||
} | ||
if permissions == 1 && !metadata.readonly() { | ||
return Ok(false); | ||
} | ||
} | ||
} | ||
if let Some(modified_time) = modified_time { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Outside the scope of this PR but in the future is it possible to add newer than or older than? Seeing this I realized it'll be be rare files match a specific second. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah that was what I was curious about with these. Do we want older/newer to be the default action? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you want to make the changes in this PR i would:
This would make it possible to time bound your search for things created within a specifir and or modified in a specific range. |
||
if path.metadata()?.modified()?.duration_since(UNIX_EPOCH)?.as_secs() != modified_time { | ||
return Ok(false); | ||
} | ||
} | ||
if let Some(create_time) = create_time { | ||
if path.metadata()?.created()?.duration_since(UNIX_EPOCH)?.as_secs() != create_time { | ||
return Ok(false); | ||
} | ||
} | ||
Ok(true) | ||
} | ||
|
||
fn search_dir(path: &str, name: Option<String>, file_type: Option<String>, permissions: Option<u64>, modified_time: Option<u64>, create_time: Option<u64>) -> Result<Vec<String>> { | ||
let mut out: Vec<String> = Vec::new(); | ||
let res = Path::new(&path); | ||
if !res.is_dir() { | ||
return Err(anyhow!("Search path is not a directory")); | ||
} | ||
if res.is_dir() { | ||
for entry in res.read_dir()? { | ||
let entry = entry?; | ||
let path = entry.path(); | ||
if path.is_dir() { | ||
out.append(&mut search_dir(path.to_str().ok_or(anyhow!("Failed to convert path to str"))?, name.clone(), file_type.clone(), permissions, modified_time, create_time)?); | ||
} else { | ||
if check_path(&path, name.clone(), file_type.clone(), permissions, modified_time, create_time)? { | ||
out.push(canonicalize(path)?.to_str().ok_or(anyhow!("Failed to convert path to str"))?.to_owned()); | ||
} | ||
} | ||
} | ||
} | ||
Ok(out) | ||
} | ||
|
||
pub fn find(path: String, name: Option<String>, file_type: Option<String>, permissions: Option<u64>, modified_time: Option<u64>, create_time: Option<u64>) -> Result<Vec<String>> { | ||
if let Some(perms) = permissions { | ||
if !cfg!(unix) && (perms != 0 || perms != 1) { | ||
return Err(anyhow::anyhow!("Only readonly permissions are available on non-unix systems. Please use 0 or 1.")); | ||
jabbate19 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
} | ||
search_dir(&path, name, file_type, permissions, modified_time, create_time) | ||
} | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could be cleaner to switch to a match.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Problem is that for unix I'm making calls to a permissions trait in
PermissionsExt
, so if we don't do this then the Windows version will try and compile with the use of the unix-only trait and errorThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couldn't it still be bound in the
#[cfg(windows)]
?I'm thinking