1 # `symlink`: create (and delete) symlinks in a cross-platform manner
3 [![Build Status](https://gitlab.com/chris-morgan/symlink/badges/master/build.svg)]
(https://gitlab.com/chris-morgan/symlink/commits/master)
4 [![Windows build status](https://ci.appveyor.com/api/projects/status/ac11k8qljgfl74vs/branch/master?svg=true)]
(https://ci.appveyor.com/project/chris-morgan/symlink/branch/master)
6 Rust’s standard library exposes platform-specific ways to create symlinks:
8 - On Windows,
`std::os::windows::fs::{symlink_file, symlink_dir}` (because Windows does file and directory symlinks differently);
9 - On Unix platforms,
`std::os::unix::fs::symlink` (because they don’t care about whether it’s a file or a directory).
11 There’s also
`std::fs::soft_link`, deprecated because of the whole Windows situation, but potentially still useful: as I write, at the start of
2022, it’s the only stable way to create a symlink on the wasm32-wasi target (
`std::os::wasi::fs::symlink_path` not yet being stable).
13 The situation is similar when removing symlinks: on most platforms all symlinks are files and must be removed with
`std::fs::remove_file`, but on Windows directory symlinks must be removed with
`std::fs::remove_dir` instead.
15 This is all a pain: as soon as you touch symlinks for Unix you need to add in lots of
`#[cfg]` branches and other such messy things, or else lose Windows support for no good reason, or use a deprecated function that makes directory symlinks not work on Windows.
17 Enter the
`symlink` crate. This crate gives you six cross-platform functions instead:
19 - `symlink_file`, which creates a file symlink on Windows and a common-or-garden symlink on other platforms;
20 - `symlink_dir`, which creates a directory symlink on Windows and a perfectly ordinary symlink on other platforms;
21 - `symlink_auto`, which creates a file or directory symlink on Windows, depending on an examination of the destination, and a perfectly ordinary symlink on other platforms;
22 - `remove_symlink_file`, which removes a file symlink on Windows and a common-or-garden symlink on other platforms;
23 - `remove_symlink_dir`, which removes a directory symlink on Windows and a perfectly ordinary symlink on other platforms;
24 - `remove_symlink_auto`, which removes a file or directory symlink on Windows, depending on an examination of the path, and a perfectly ordinary symlink on other platforms.
26 Back on the topic of
`std::fs::soft_link`: it got deprecated in Rust
1.1.0 because it just created a file symlink on Windows, which is often wrong.
`symlink_auto` creates a file *or* directory symlink, depending on what the target is. (But it’s also more fragile: unlike
`symlink_file` and
`symlink_dir`, it returns an error if the destination doesn’t exist or can’t be statted.)
28 And before this crate there was no good way to delete a symlink at all on Windows. Who knows, perhaps windows_file_type_ext will be stabilised eventually. But until then, there’s this crate.
32 You should generally avoid
`symlink_auto` and
`remove_symlink_auto`, preferring to use the more specific
`symlink_file` or
`symlink_dir` and
`remove_symlink_file` or
`remove_symlink_dir`, whichever seems appropriate for what you’re doing. (In real life you almost always know whether you’re making a file or a directory symlink, so say it in the code!)
34 **Make sure you use absolute paths for the destination.** I haven’t tested whether relative paths are treated consistently across platforms yet (whether they’re relative to the working directory or the symlink source path). TODO!
36 ## Caution: symlinks are still less reliable on Windows
38 You can only reliably use symlinks from the Windows
10 Creators Update (mid-
2017) onwards.
40 Before that, manipulating symlinks required a special privilege which practically meant you had to run a program as admin to get it to work. And symlinks were new to Vista; XP and older didn’t support them.
42 ## My goal: integration with Rust
44 I would like to merge this into libstd in some form, because the symlink manipulation support in the standard library at present is hopeless for cross-platformness. I haven’t written an RFC yet; it should definitely start as a separate crate (that’s what this is). Here are some of my thoughts:
46 **Concerning
`symlink_auto`**: it’s deliberately not named
`symlink`; my hope is that people won’t just reach for it blindly but will think about what they are doing. A few things can happen to it (in my order of preference):
48 1. It can not exist. It’s really not *necessary*, and letting people be lazy isn’t always good. Encourage cross-platformness!
49 2. It can exist as
`std::fs::symlink_auto`. The distinction is thus clear.
50 3.
`std::fs::soft_link` can be undeprecated, with a change to its Windows semantics from “make a file symlink” to “make a file or directory symlink as appropriate, yielding an error if the destination doesn’t stat”.
51 4.
`std::fs::soft_link` can be undeprecated, with a change to its Windows semantics from “make a file symlink” to “make a file or directory symlink as appropriate, going with a file symlink if the destination doesn’t stat”.
52 5. It can exist as
`std::fs::symlink`. This is the obvious name, but as mentioned earlier encourages inefficient imprecision for Windows.
54 **Concerning
`symlink_dir` and
`symlink_file`**:
56 1.
`std::fs::{symlink_file, symlink_dir}`, matching
`symlink_auto` or nothing.
58 2.
`std::fs::{soft_link_file, soft_link_dir}`, matching
`soft_link` if it is undeprecated. But I don’t like the name “soft link,” anyway: no one calls them that, we all call them symlinks.
60 Note that despite the suggestions matching certain approaches for
`symlink_auto`, the choices are still independent; there are ten viable combinations presented.
62 **Concerning
`remove_*`**: I guess what’s done with the other three functions will guide what’s done with these three.
64 ## Unsafe code in this library
66 On Windows only there is some unavoidable unsafe code in
`remove_symlink_auto` to determine whether a symlink is a file symlink or a directory symlink, because this detail is not exposed in a stable function in the standard library.
70 [Chris Morgan](https://chrismorgan.info/) is the author and maintainer of this library.
74 Copyright ©
2017–
2022 Chris Morgan
76 This project is distributed under the terms of three different licenses,
79 - Blue Oak Model License
1.0.0: https://blueoakcouncil.org/license/
1.0.0
80 - MIT License: https://opensource.org/licenses/MIT
81 - Apache License, Version
2.0: https://www.apache.org/licenses/LICENSE-
2.0
83 If you do not have particular cause to select the MIT or the Apache-
2.0
84 license, Chris Morgan recommends that you select BlueOak-
1.0.0, which is
85 better and simpler than both MIT and Apache-
2.0, which are only offered
86 due to their greater recognition and their conventional use in the Rust
87 ecosystem. (BlueOak-
1.0.0 was only published in March
2019.)
89 When using this code, ensure you comply with the terms of at least one of