Skip to content

Commit 8ab2e3c

Browse files
authored
refactor(core): simplify and document push_pattern (#11065)
1 parent 9014a3f commit 8ab2e3c

File tree

1 file changed

+58
-47
lines changed
  • crates/tauri/src/scope

1 file changed

+58
-47
lines changed

crates/tauri/src/scope/fs.rs

Lines changed: 58 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -77,74 +77,85 @@ fn push_pattern<P: AsRef<Path>, F: Fn(&str) -> Result<Pattern, glob::PatternErro
7777
pattern: P,
7878
f: F,
7979
) -> crate::Result<()> {
80-
let mut path: PathBuf = dunce::simplified(pattern.as_ref()).components().collect();
81-
82-
if cfg!(windows) {
83-
// Canonicalize disk-relative paths before inserting into the list
84-
use std::path::{Component, Prefix};
85-
let mut components = path.components();
86-
if let Some(Component::Prefix(prefix)) = components.next() {
87-
if matches!(prefix.kind(), Prefix::Disk(_) | Prefix::VerbatimDisk(_))
88-
&& !matches!(components.next(), Some(Component::RootDir))
89-
{
90-
path = dunce::simplified(&path.canonicalize()?).to_path_buf();
80+
// Reconstruct pattern path components with appropraite separator
81+
// so `some\path/to/dir/**\*` would be `some/path/to/dir/**/*` on Unix
82+
// and `some\path\to\dir\**\*` on Windows.
83+
let path: PathBuf = pattern.as_ref().components().collect();
84+
85+
// Add pattern as is to be matched with paths as is
86+
let path_str = path.to_string_lossy();
87+
list.insert(f(&path_str)?);
88+
89+
// On Windows, if path starts with a Prefix, try to strip it if possible
90+
// so `\\?\C:\\SomeDir` would result in a scope of:
91+
// - `\\?\C:\\SomeDir`
92+
// - `C:\\SomeDir`
93+
#[cfg(windows)]
94+
{
95+
use std::path::Component;
96+
97+
if matches!(path.components().next(), Some(Component::Prefix(_))) {
98+
let simplified = dunce::simplified(&path);
99+
let simplified_str = simplified.to_string_lossy();
100+
if simplified_str != path_str {
101+
list.insert(f(&simplified_str)?);
91102
}
92103
}
93104
}
94105

95-
list.insert(f(&path.to_string_lossy())?);
96-
97-
let mut checked_path = None;
98-
99-
// attempt to canonicalize parents in case we have a path like `/data/user/0/appid/**`
100-
// where `**` obviously does not exist but we need to canonicalize the parent
101-
//
102-
// example: given the `/data/user/0/appid/assets/*` path,
103-
// it's a glob pattern so it won't exist (canonicalize() fails);
104-
//
105-
// the second iteration needs to check `/data/user/0/appid/assets` and save the `*` component to append later.
106-
//
107-
// if it also does not exist, a third iteration is required to check `/data/user/0/appid`
108-
// with `assets/*` as the cached value (`checked_path` variable)
109-
// on Android that gets canonicalized to `/data/data/appid` so the final value will be `/data/data/appid/assets/*`
110-
// which is the value we want to check when we execute the `is_allowed` function
111-
let canonicalized = loop {
106+
// Add canonicalized version of the pattern or canonicalized version of its parents
107+
// so `/data/user/0/appid/assets/*` would be canonicalized to `/data/data/appid/assets/*`
108+
// and can then be matched against any of them.
109+
if let Some(p) = canonicalize_parent(path) {
110+
list.insert(f(&p.to_string_lossy())?);
111+
}
112+
113+
Ok(())
114+
}
115+
116+
/// Attempt to canonicalize path or its parents in case we have a path like `/data/user/0/appid/**`
117+
/// where `**` obviously does not exist but we need to canonicalize the parent.
118+
///
119+
/// example: given the `/data/user/0/appid/assets/*` path,
120+
/// it's a glob pattern so it won't exist (std::fs::canonicalize() fails);
121+
///
122+
/// the second iteration needs to check `/data/user/0/appid/assets` and save the `*` component to append later.
123+
///
124+
/// if it also does not exist, a third iteration is required to check `/data/user/0/appid`
125+
/// with `assets/*` as the cached value (`checked_path` variable)
126+
/// on Android that gets canonicalized to `/data/data/appid` so the final value will be `/data/data/appid/assets/*`
127+
/// which is the value we want to check when we execute the `Scope::is_allowed` function
128+
fn canonicalize_parent(mut path: PathBuf) -> Option<PathBuf> {
129+
let mut failed_components = None;
130+
131+
loop {
112132
if let Ok(path) = path.canonicalize() {
113-
break Some(if let Some(p) = checked_path {
133+
break Some(if let Some(p) = failed_components {
114134
path.join(p)
115135
} else {
116136
path
117137
});
118138
}
119139

120-
// get the last component of the path as an OsStr
121-
let last = path.iter().next_back().map(PathBuf::from);
122-
if let Some(mut p) = last {
123-
// remove the last component of the path
124-
// so the next iteration checks its parent
140+
// grap the last component of the path
141+
if let Some(mut last) = path.iter().next_back().map(PathBuf::from) {
142+
// remove the last component of the path so the next iteration checks its parent
143+
// if there is no more parent components, we failed to canonicalize
125144
if !path.pop() {
126145
break None;
127146
}
147+
128148
// append the already checked path to the last component
129-
if let Some(checked_path) = &checked_path {
130-
p.push(checked_path);
149+
// to construct `<last>/<checked_path>` and saved it for next iteration
150+
if let Some(failed_components) = &failed_components {
151+
last.push(failed_components);
131152
}
132-
// replace the checked path with the current value
133-
checked_path.replace(p);
153+
failed_components.replace(last);
134154
} else {
135155
break None;
136156
}
137-
};
138-
139-
if let Some(p) = canonicalized {
140-
list.insert(f(&p.to_string_lossy())?);
141-
} else if cfg!(windows) && !path.to_string_lossy().starts_with("\\\\") {
142-
list.insert(f(&format!("\\\\?\\{}", path.display()))?);
143157
}
144-
145-
Ok(())
146158
}
147-
148159
impl Scope {
149160
/// Creates a new scope from a [`FsScope`] configuration.
150161
pub fn new<R: crate::Runtime, M: crate::Manager<R>>(

0 commit comments

Comments
 (0)