rollup merge of #24222: lambda/rename-soft-link-to-symlink

Implement [RFC #1048][rfc].

On Windows, when you create a symbolic link you must specify whether it
points to a directory or a file, even if it is created dangling, while
on Unix, the same symbolic link could point to a directory, a file, or
nothing at all.  Furthermore, on Windows special privilege is necessary
to use a symbolic link, while on Unix, you can generally create a
symbolic link in any directory you have write privileges to.

This means that it is unlikely to be able to use symbolic links purely
portably; anyone who uses them will need to think about the cross
platform implications.  This means that using platform-specific APIs
will make it easier to see where code will need to differ between the
platforms, rather than trying to provide some kind of compatibility
wrapper.

Furthermore, `soft_link` has no precedence in any other API, so to avoid
confusion, move back to the more standard `symlink` terminology.

Create a `std::os::unix::symlink` for the Unix version that is
destination type agnostic, as well as `std::os::windows::{symlink_file,
symlink_dir}` for Windows.

Because this is a stable API, leave a compatibility wrapper in
`std::fs::soft_link`, which calls `symlink` on Unix and `symlink_file`
on Windows, preserving the existing behavior of `soft_link`.

[rfc]: https://github.com/rust-lang/rfcs/pull/1048
This commit is contained in:
Alex Crichton 2015-04-21 15:23:06 -07:00
commit 2fc2e12687
5 changed files with 104 additions and 8 deletions

View File

@ -706,7 +706,7 @@ pub fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> {
/// Given a path, query the file system to get information about a file,
/// directory, etc.
///
/// This function will traverse soft links to query information about the
/// This function will traverse symbolic links to query information about the
/// destination file.
///
/// # Examples
@ -820,9 +820,13 @@ pub fn hard_link<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<(
fs_imp::link(src.as_ref(), dst.as_ref())
}
/// Creates a new soft link on the filesystem.
/// Creates a new symbolic link on the filesystem.
///
/// The `dst` path will be a soft link pointing to the `src` path.
/// The `dst` path will be a symbolic link pointing to the `src` path.
/// On Windows, this will be a file symlink, not a directory symlink;
/// for this reason, the platform-specific `std::os::unix::fs::symlink`
/// and `std::os::windows::fs::{symlink_file, symlink_dir}` should be
/// used instead to make the intent explicit.
///
/// # Examples
///
@ -834,17 +838,20 @@ pub fn hard_link<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<(
/// # Ok(())
/// # }
/// ```
#[deprecated(since = "1.0.0",
reason = "replaced with std::os::unix::fs::symlink and \
std::os::windows::fs::{symlink_file, symlink_dir}")]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn soft_link<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
fs_imp::symlink(src.as_ref(), dst.as_ref())
}
/// Reads a soft link, returning the file that the link points to.
/// Reads a symbolic link, returning the file that the link points to.
///
/// # Errors
///
/// This function will return an error on failure. Failure conditions include
/// reading a file that does not exist or reading a file that is not a soft
/// reading a file that does not exist or reading a file that is not a symbolic
/// link.
///
/// # Examples
@ -937,8 +944,8 @@ pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
/// Removes a directory at this path, after removing all its contents. Use
/// carefully!
///
/// This function does **not** follow soft links and it will simply remove the
/// soft link itself.
/// This function does **not** follow symbolic links and it will simply remove the
/// symbolic link itself.
///
/// # Errors
///

View File

@ -189,8 +189,12 @@ pub mod ffi {
#[unstable(feature = "fs_ext",
reason = "may want a more useful mode abstraction")]
pub mod fs {
use sys;
use sys_common::{FromInner, AsInner, AsInnerMut};
use fs::{Permissions, OpenOptions};
use path::Path;
use convert::AsRef;
use io;
/// Unix-specific extensions to `Permissions`
pub trait PermissionsExt {
@ -220,6 +224,36 @@ pub mod fs {
self.as_inner_mut().mode(mode); self
}
}
/// Creates a new symbolic link on the filesystem.
///
/// The `dst` path will be a symbolic link pointing to the `src` path.
///
/// # Note
///
/// On Windows, you must specify whether a symbolic link points to a file
/// or directory. Use `os::windows::fs::symlink_file` to create a
/// symbolic link to a file, or `os::windows::fs::symlink_dir` to create a
/// symbolic link to a directory. Additionally, the process must have
/// `SeCreateSymbolicLinkPrivilege` in order to be able to create a
/// symbolic link.
///
/// # Examples
///
/// ```
/// #![feature(fs_ext)]
/// use std::os::unix::fs;
///
/// # fn foo() -> std::io::Result<()> {
/// try!(fs::symlink("a.txt", "b.txt"));
/// # Ok(())
/// # }
/// ```
pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()>
{
sys::fs2::symlink(src.as_ref(), dst.as_ref())
}
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -54,6 +54,8 @@ pub const MAXIMUM_REPARSE_DATA_BUFFER_SIZE: usize = 16 * 1024;
pub const FSCTL_GET_REPARSE_POINT: libc::DWORD = 0x900a8;
pub const IO_REPARSE_TAG_SYMLINK: libc::DWORD = 0xa000000c;
pub const SYMBOLIC_LINK_FLAG_DIRECTORY: libc::DWORD = 0x1;
// Note that these are not actually HANDLEs, just values to pass to GetStdHandle
pub const STD_INPUT_HANDLE: libc::DWORD = -10i32 as libc::DWORD;
pub const STD_OUTPUT_HANDLE: libc::DWORD = -11i32 as libc::DWORD;

View File

@ -191,7 +191,11 @@ pub mod ffi {
#[unstable(feature = "fs_ext", reason = "may require more thought/methods")]
pub mod fs {
use fs::OpenOptions;
use sys;
use sys_common::AsInnerMut;
use path::Path;
use convert::AsRef;
use io;
/// Windows-specific extensions to `OpenOptions`
pub trait OpenOptionsExt {
@ -235,6 +239,50 @@ pub mod fs {
self.as_inner_mut().share_mode(access); self
}
}
/// Creates a new file symbolic link on the filesystem.
///
/// The `dst` path will be a file symbolic link pointing to the `src`
/// path.
///
/// # Examples
///
/// ```ignore
/// #![feature(fs_ext)]
/// use std::os::windows::fs;
///
/// # fn foo() -> std::io::Result<()> {
/// try!(fs::symlink_file("a.txt", "b.txt"));
/// # Ok(())
/// # }
/// ```
pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q)
-> io::Result<()>
{
sys::fs2::symlink_inner(src.as_ref(), dst.as_ref(), false)
}
/// Creates a new directory symlink on the filesystem.
///
/// The `dst` path will be a directory symbolic link pointing to the `src`
/// path.
///
/// # Examples
///
/// ```ignore
/// #![feature(fs_ext)]
/// use std::os::windows::fs;
///
/// # fn foo() -> std::io::Result<()> {
/// try!(fs::symlink_file("a", "b"));
/// # Ok(())
/// # }
/// ```
pub fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>> (src: P, dst: Q)
-> io::Result<()>
{
sys::fs2::symlink_inner(src.as_ref(), dst.as_ref(), true)
}
}
/// A prelude for conveniently writing platform-specific code.

View File

@ -412,11 +412,16 @@ pub fn readlink(p: &Path) -> io::Result<PathBuf> {
}
pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> {
symlink_inner(src, dst, false)
}
pub fn symlink_inner(src: &Path, dst: &Path, dir: bool) -> io::Result<()> {
use sys::c::compat::kernel32::CreateSymbolicLinkW;
let src = to_utf16(src);
let dst = to_utf16(dst);
let flags = if dir { c::SYMBOLIC_LINK_FLAG_DIRECTORY } else { 0 };
try!(cvt(unsafe {
CreateSymbolicLinkW(dst.as_ptr(), src.as_ptr(), 0) as libc::BOOL
CreateSymbolicLinkW(dst.as_ptr(), src.as_ptr(), flags) as libc::BOOL
}));
Ok(())
}