diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 6e902a4739623..2364e1d42bbe3 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -700,7 +700,7 @@ pub fn remove_file>(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 @@ -814,9 +814,13 @@ pub fn hard_link, Q: AsRef>(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 /// @@ -828,17 +832,20 @@ pub fn hard_link, Q: AsRef>(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, Q: AsRef>(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 @@ -931,8 +938,8 @@ pub fn remove_dir>(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 /// diff --git a/src/libstd/sys/unix/ext.rs b/src/libstd/sys/unix/ext.rs index 032fd33b1d348..9504fe6369788 100644 --- a/src/libstd/sys/unix/ext.rs +++ b/src/libstd/sys/unix/ext.rs @@ -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, Q: AsRef>(src: P, dst: Q) -> io::Result<()> + { + sys::fs2::symlink(src.as_ref(), dst.as_ref()) + } + } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index 45f389f0aebf8..331bfbfff36f9 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -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; diff --git a/src/libstd/sys/windows/ext.rs b/src/libstd/sys/windows/ext.rs index 90548dcefb483..eac6496870eab 100644 --- a/src/libstd/sys/windows/ext.rs +++ b/src/libstd/sys/windows/ext.rs @@ -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, Q: AsRef>(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, Q: AsRef> (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. diff --git a/src/libstd/sys/windows/fs2.rs b/src/libstd/sys/windows/fs2.rs index 9645c51ec0b23..90daae3dea41a 100644 --- a/src/libstd/sys/windows/fs2.rs +++ b/src/libstd/sys/windows/fs2.rs @@ -402,11 +402,16 @@ pub fn readlink(p: &Path) -> io::Result { } 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(()) }