Skip to content

Commit 19533e7

Browse files
committed
Dont canonicalize per default
1 parent 9e0af87 commit 19533e7

1 file changed

Lines changed: 28 additions & 120 deletions

File tree

src/shortcut.rs

Lines changed: 28 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::{
22
borrow::Cow,
3+
io,
34
path::{Path, PathBuf},
45
ptr,
56
};
@@ -52,32 +53,6 @@ pub struct Shortcut {
5253
pub run_as_admin: bool,
5354
}
5455

55-
/// Options for loading a [`Shortcut`], can be specified when using [`load_with_options`](Shortcut::load_with_options).
56-
#[derive(Debug, Clone, Copy)]
57-
pub struct LoadOptions {
58-
/// If true, canonicalizes paths.
59-
pub canonicalize: bool,
60-
}
61-
62-
impl Default for LoadOptions {
63-
fn default() -> Self {
64-
Self { canonicalize: true } // keep current behavior as default
65-
}
66-
}
67-
68-
/// Options for saving a [`Shortcut`], can be specified when using [`save_with_options`](Shortcut::save_with_options).
69-
#[derive(Debug, Clone, Copy)]
70-
pub struct SaveOptions {
71-
/// If true, canonicalizes paths.
72-
pub canonicalize: bool,
73-
}
74-
75-
impl Default for SaveOptions {
76-
fn default() -> Self {
77-
Self { canonicalize: true }
78-
}
79-
}
80-
8156
impl Shortcut {
8257
/// Create a new empty [`ShortcutBuilder`].
8358
#[must_use]
@@ -100,11 +75,6 @@ impl Shortcut {
10075
}
10176
}
10277

103-
/// Loads a `.lnk` file from disk and parses it into a [`Shortcut`].
104-
pub fn load(path: impl AsRef<Path>) -> Result<Self> {
105-
Self::load_with_options(path, LoadOptions::default())
106-
}
107-
10878
/// Canonicalizes all filesystem paths contained in this shortcut in-place.
10979
///
11080
/// The following fields are affected:
@@ -116,27 +86,25 @@ impl Shortcut {
11686
/// If a path is **relative** and `base` is [`Some`], it is first resolved
11787
/// relative to `base` (typically the directory containing the `.lnk` file)
11888
/// and then canonicalized.
119-
///
120-
/// # Errors
121-
/// Errors during canonicalization are ignored.
122-
pub fn canonicalize(&mut self, base: Option<&Path>) {
123-
try_canonicalize_with_base_inplace_opt(self.target_path.as_mut(), base);
124-
try_canonicalize_with_base_inplace_opt(self.working_dir.as_mut(), base);
125-
try_canonicalize_with_base_inplace_opt(self.icon.as_mut().map(|i| &mut i.path), base);
89+
pub fn canonicalize(&mut self, base: Option<&Path>) -> io::Result<()> {
90+
canonicalize_with_base_inplace_opt(self.target_path.as_mut(), base)?;
91+
canonicalize_with_base_inplace_opt(self.working_dir.as_mut(), base)?;
92+
canonicalize_with_base_inplace_opt(self.icon.as_mut().map(|i| &mut i.path), base)?;
93+
Ok(())
12694
}
12795

12896
/// Returns a canonicalized clone of this shortcut.
12997
///
13098
/// This is a non-mutating variant of [`canonicalize`](Self::canonicalize).
13199
/// The original [`Shortcut`] is left unchanged.
132-
pub fn canonicalized(&self, base: Option<&Path>) -> Self {
100+
pub fn canonicalized(&self, base: Option<&Path>) -> io::Result<Self> {
133101
let mut clone = self.clone();
134-
clone.canonicalize(base);
135-
clone
102+
clone.canonicalize(base)?;
103+
Ok(clone)
136104
}
137105

138-
/// Loads a `.lnk` file from disk and parses it into a [`Shortcut`], considering the given [`LoadOptions`].
139-
pub fn load_with_options(path: impl AsRef<Path>, options: LoadOptions) -> Result<Self> {
106+
/// Loads a `.lnk` file from disk and parses it into a [`Shortcut`].
107+
pub fn load(path: impl AsRef<Path>) -> Result<Self> {
140108
let path = path.as_ref();
141109
com::ensure_initialized()?;
142110

@@ -181,7 +149,7 @@ impl Shortcut {
181149
#[cfg(feature = "runas")]
182150
let run_as_admin = runas::read_runas_bit(&path)?;
183151

184-
let mut shortcut = Shortcut {
152+
let shortcut = Shortcut {
185153
target_path,
186154
arguments,
187155
working_dir,
@@ -193,31 +161,19 @@ impl Shortcut {
193161
run_as_admin,
194162
};
195163

196-
if options.canonicalize {
197-
shortcut.canonicalize(path.parent());
198-
}
199-
200164
Ok(shortcut)
201165
}
202166

203167
/// Saves the shortcut to disk as a `.lnk` file.
204168
pub fn save(&self, path: impl AsRef<Path>) -> Result<()> {
205-
self.save_with_options(path, SaveOptions::default())
206-
}
207-
208-
/// Saves the shortcut to disk as a `.lnk` file, considering the given [`SaveOptions`].
209-
pub fn save_with_options(&self, path: impl AsRef<Path>, options: SaveOptions) -> Result<()> {
210169
com::ensure_initialized()?;
211170

212-
let path = maybe_try_canonicalize(path.as_ref(), options.canonicalize);
213-
let base = path.parent();
171+
let path = try_canonicalize(path.as_ref());
214172

215173
let link: IShellLinkW = unsafe { CoCreateInstance(&ShellLink, None, CLSCTX_INPROC_SERVER) }
216174
.context(None, "CoCreateInstance")?;
217175

218176
if let Some(target_path) = &self.target_path {
219-
let target_path =
220-
maybe_try_canonicalize_with_base(target_path, base, options.canonicalize);
221177
let w = U16CString::from_os_str(target_path.as_os_str())?;
222178
unsafe { link.SetPath(PCWSTR(w.as_ptr())) }.context(Some("IShellLinkW"), "SetPath")?;
223179
}
@@ -229,8 +185,6 @@ impl Shortcut {
229185
}
230186

231187
if let Some(working_dir) = &self.working_dir {
232-
let working_dir =
233-
maybe_try_canonicalize_with_base(working_dir, base, options.canonicalize);
234188
let w = U16CString::from_os_str(working_dir.as_os_str())?;
235189
unsafe { link.SetWorkingDirectory(PCWSTR(w.as_ptr())) }
236190
.context(Some("IShellLinkW"), "SetWorkingDirectory")?;
@@ -243,9 +197,7 @@ impl Shortcut {
243197
}
244198

245199
if let Some(icon) = &self.icon {
246-
let icon_path =
247-
maybe_try_canonicalize_with_base(&icon.path, base, options.canonicalize);
248-
let w = U16CString::from_os_str(icon_path.as_os_str())?;
200+
let w = U16CString::from_os_str(icon.path.as_os_str())?;
249201
unsafe { link.SetIconLocation(PCWSTR(w.as_ptr()), icon.index) }
250202
.context(Some("IShellLinkW"), "SetIconLocation")?;
251203
}
@@ -400,76 +352,32 @@ impl ShortcutBuilder {
400352
}
401353
}
402354

403-
fn try_canonicalize_inplace(path: &mut PathBuf) -> bool {
404-
if let Ok(canon) = dunce::canonicalize(&path) {
405-
*path = canon;
406-
true
407-
} else {
408-
false
409-
}
410-
}
411-
/*
412-
fn try_canonicalize_inplace_opt(opt: Option<&mut PathBuf>) -> bool {
413-
if let Some(path) = opt {
414-
try_canonicalize_inplace(path)
415-
} else {
416-
false
417-
}
355+
fn canonicalize_inplace(path: &mut PathBuf) -> io::Result<()> {
356+
*path = dunce::canonicalize(&path)?;
357+
Ok(())
418358
}
419-
*/
420359
#[allow(clippy::unnecessary_unwrap)]
421-
fn try_canonicalize_with_base_inplace(path: &mut PathBuf, base: Option<&Path>) -> bool {
360+
fn canonicalize_with_base_inplace(path: &mut PathBuf, base: Option<&Path>) -> io::Result<()> {
422361
if path.is_absolute() || base.is_none() {
423-
try_canonicalize_inplace(path)
362+
canonicalize_inplace(path)
424363
} else {
425364
let mut absolute = base.unwrap().join(&path);
426-
let success = try_canonicalize_inplace(&mut absolute);
427-
if success {
428-
*path = absolute;
429-
}
430-
success
365+
canonicalize_inplace(&mut absolute)?;
366+
*path = absolute;
367+
Ok(())
431368
}
432369
}
433-
fn try_canonicalize_with_base_inplace_opt(opt: Option<&mut PathBuf>, base: Option<&Path>) -> bool {
370+
fn canonicalize_with_base_inplace_opt(
371+
opt: Option<&mut PathBuf>,
372+
base: Option<&Path>,
373+
) -> io::Result<()> {
434374
if let Some(path) = opt {
435-
try_canonicalize_with_base_inplace(path, base)
375+
canonicalize_with_base_inplace(path, base)
436376
} else {
437-
false
377+
Ok(())
438378
}
439379
}
440380

441381
fn try_canonicalize(path: &'_ Path) -> Cow<'_, Path> {
442382
dunce::canonicalize(path).map_or_else(|_| Cow::Borrowed(path), Cow::Owned)
443383
}
444-
fn maybe_try_canonicalize(path: &'_ Path, enabled: bool) -> Cow<'_, Path> {
445-
if enabled {
446-
try_canonicalize(path)
447-
} else {
448-
Cow::Borrowed(path)
449-
}
450-
}
451-
452-
#[allow(clippy::unnecessary_unwrap)]
453-
fn try_canonicalize_with_base<'a>(path: &'a Path, base: Option<&'_ Path>) -> Cow<'a, Path> {
454-
if path.is_absolute() || base.is_none() {
455-
try_canonicalize(path)
456-
} else {
457-
let mut absolute = base.unwrap().join(path);
458-
if try_canonicalize_inplace(&mut absolute) {
459-
Cow::Owned(absolute)
460-
} else {
461-
Cow::Borrowed(path)
462-
}
463-
}
464-
}
465-
fn maybe_try_canonicalize_with_base<'a>(
466-
path: &'a Path,
467-
base: Option<&'_ Path>,
468-
enabled: bool,
469-
) -> Cow<'a, Path> {
470-
if enabled {
471-
try_canonicalize_with_base(path, base)
472-
} else {
473-
Cow::Borrowed(path)
474-
}
475-
}

0 commit comments

Comments
 (0)