diff options
| author | Dylan DPC <dylan.dpc@gmail.com> | 2020-11-09 01:13:28 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-11-09 01:13:28 +0100 |
| commit | 41134be153ec0e152b0bb5cf79731abdde7c4e04 (patch) | |
| tree | 711a7cbc785c67e8bc87613a2d13200d2bcdb210 /library/std/src/sys | |
| parent | d69ee57f977d03644acd8fbfd1799410e2c02db3 (diff) | |
| parent | 6249cda78f0cd32b60fb11702b7ffef3e3bab0b2 (diff) | |
| download | rust-41134be153ec0e152b0bb5cf79731abdde7c4e04.tar.gz rust-41134be153ec0e152b0bb5cf79731abdde7c4e04.zip | |
Rollup merge of #78026 - sunfishcode:symlink-hard-link, r=dtolnay
Define `fs::hard_link` to not follow symlinks. POSIX leaves it [implementation-defined] whether `link` follows symlinks. In practice, for example, on Linux it does not and on FreeBSD it does. So, switch to `linkat`, so that we can pick a behavior rather than depending on OS defaults. Pick the option to not follow symlinks. This is somewhat arbitrary, but seems the less surprising choice because hard linking is a very low-level feature which requires the source and destination to be on the same mounted filesystem, and following a symbolic link could end up in a different mounted filesystem. [implementation-defined]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/link.html
Diffstat (limited to 'library/std/src/sys')
| -rw-r--r-- | library/std/src/sys/unix/fs.rs | 15 |
1 files changed, 14 insertions, 1 deletions
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index d27d6e2c565..96594095cc3 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -1081,7 +1081,20 @@ pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> { pub fn link(src: &Path, dst: &Path) -> io::Result<()> { let src = cstr(src)?; let dst = cstr(dst)?; - cvt(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) })?; + cfg_if::cfg_if! { + if #[cfg(any(target_os = "vxworks", target_os = "redox", target_os = "android"))] { + // VxWorks, Redox, and old versions of Android lack `linkat`, so use + // `link` instead. POSIX leaves it implementation-defined whether + // `link` follows symlinks, so rely on the `symlink_hard_link` test + // in library/std/src/fs/tests.rs to check the behavior. + cvt(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) })?; + } else { + // Use `linkat` with `AT_FDCWD` instead of `link` as `linkat` gives + // us a flag to specify how symlinks should be handled. Pass 0 as + // the flags argument, meaning don't follow symlinks. + cvt(unsafe { libc::linkat(libc::AT_FDCWD, src.as_ptr(), libc::AT_FDCWD, dst.as_ptr(), 0) })?; + } + } Ok(()) } |
