diff --git a/CHANGELOG.md b/CHANGELOG.md
index 972b998715..6f408ca09a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -21,6 +21,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
   ([#1058](https://github.com/nix-rust/nix/pull/1058))
 - Add `renameat`.
   ([#1097](https://github.com/nix-rust/nix/pull/1097))
+- Add `linkat`
+  ([#1101](https://github.com/nix-rust/nix/pull/1101))
 
 ### Changed
 - Support for `ifaddrs` now present when building for Android.
diff --git a/src/fcntl.rs b/src/fcntl.rs
index be6ee0f73a..d8e68123cb 100644
--- a/src/fcntl.rs
+++ b/src/fcntl.rs
@@ -24,6 +24,7 @@ pub use self::posix_fadvise::*;
 libc_bitflags!{
     pub struct AtFlags: c_int {
         AT_REMOVEDIR;
+        AT_SYMLINK_FOLLOW;
         AT_SYMLINK_NOFOLLOW;
         #[cfg(any(target_os = "android", target_os = "linux"))]
         AT_NO_AUTOMOUNT;
diff --git a/src/unistd.rs b/src/unistd.rs
index f422f09198..20e3c1356f 100644
--- a/src/unistd.rs
+++ b/src/unistd.rs
@@ -1132,6 +1132,57 @@ pub fn isatty(fd: RawFd) -> Result<bool> {
     }
 }
 
+/// Flags for `linkat` function.
+#[derive(Clone, Copy, Debug)]
+pub enum LinkatFlags {
+    SymlinkFollow,
+    NoSymlinkFollow,
+}
+
+/// Link one file to another file
+///
+/// Creates a new link (directory entry) at `newpath` for the existing file at `oldpath`. In the 
+/// case of a relative `oldpath`, the path is interpreted relative to the directory associated 
+/// with file descriptor `olddirfd` instead of the current working directory and similiarly for 
+/// `newpath` and file descriptor `newdirfd`. In case `flag` is LinkatFlags::SymlinkFollow and 
+/// `oldpath` names a symoblic link, a new link for the target of the symbolic link is created.
+/// The function shall fail if either olddirfd or newdirfd is None, returning ENOENT and EEXIST 
+/// for olddirfd and newdirfd respectively.
+///
+/// # References
+/// See also [linkat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/linkat.html)
+pub fn linkat<P: ?Sized + NixPath>(
+    olddirfd: Option<RawFd>,
+    oldpath: &P,
+    newdirfd: Option<RawFd>,
+    newpath: &P,   
+    flag: LinkatFlags,
+) -> Result<()> {
+    
+    let atflag =
+        match flag {
+            LinkatFlags::SymlinkFollow => AtFlags::AT_SYMLINK_FOLLOW,
+            LinkatFlags::NoSymlinkFollow => AtFlags::empty(),
+        };
+
+    let res = 
+        oldpath.with_nix_path(|oldcstr| {
+            newpath.with_nix_path(|newcstr| {
+            unsafe {
+                libc::linkat(
+                    at_rawfd(olddirfd), 
+                    oldcstr.as_ptr(), 
+                    at_rawfd(newdirfd), 
+                    newcstr.as_ptr(), 
+                    atflag.bits() as libc::c_int
+                    )
+                }
+            })
+        })??;
+    Errno::result(res).map(drop)
+}
+
+
 /// Remove a directory entry
 ///
 /// See also [unlink(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/unlink.html)
diff --git a/test/test_unistd.rs b/test/test_unistd.rs
index 46196dec7c..0af4b06f3e 100644
--- a/test/test_unistd.rs
+++ b/test/test_unistd.rs
@@ -601,6 +601,95 @@ fn test_symlinkat() {
 }
 
 
+#[test]
+fn test_linkat_file() {
+    let tempdir = tempfile::tempdir().unwrap();
+    let oldfilename = "foo.txt";
+    let oldfilepath = tempdir.path().join(oldfilename);
+
+    let newfilename = "bar.txt";
+    let newfilepath = tempdir.path().join(newfilename);
+
+    // Create file
+    File::create(&oldfilepath).unwrap();
+
+    // Get file descriptor for base directory
+    let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap();
+
+    // Attempt hard link file at relative path
+    linkat(Some(dirfd), oldfilename, Some(dirfd), newfilename, LinkatFlags::SymlinkFollow).unwrap();
+    assert!(newfilepath.exists());
+}
+
+#[cfg(not(any(target_os = "ios", target_os = "macos")))]
+#[test]
+fn test_linkat_no_follow_symlink() {
+    let mut buf = [0; 1024];
+    let tempdir = tempfile::tempdir().unwrap();
+    let oldfilename = "foo.txt";
+    let oldfilepath = tempdir.path().join(oldfilename);
+
+    let symoldfilename = "symfoo.txt";
+    let symoldfilepath = tempdir.path().join(symoldfilename);
+
+    let newfilename = "nofollowsymbar.txt";
+    let newfilepath = tempdir.path().join(newfilename);
+
+    // Create file
+    File::create(&oldfilepath).unwrap();
+
+    // Create symlink to file
+    symlinkat(&oldfilepath, None, &symoldfilepath).unwrap();
+
+    // Get file descriptor for base directory
+    let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap();
+
+    // Attempt link symlink of file at relative path
+    linkat(Some(dirfd), symoldfilename, Some(dirfd), newfilename, LinkatFlags::NoSymlinkFollow).unwrap();
+
+    // Assert newfile is actually a symlink to oldfile.
+    assert_eq!(
+        readlink(&newfilepath, &mut buf)
+            .unwrap()
+            .to_str()
+            .unwrap(),
+        oldfilepath.to_str().unwrap()
+    );
+}
+
+#[test]
+fn test_linkat_follow_symlink() {
+    let tempdir = tempfile::tempdir().unwrap();
+    let oldfilename = "foo.txt";
+    let oldfilepath = tempdir.path().join(oldfilename);
+
+    let symoldfilename = "symfoo.txt";
+    let symoldfilepath = tempdir.path().join(symoldfilename);
+
+    let newfilename = "nofollowsymbar.txt";
+    let newfilepath = tempdir.path().join(newfilename);
+
+    // Create file
+    File::create(&oldfilepath).unwrap();
+
+    // Create symlink to file
+    symlinkat(&oldfilepath, None, &symoldfilepath).unwrap();
+
+    // Get file descriptor for base directory
+    let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap();
+
+    // Attempt link target of symlink of file at relative path
+    linkat(Some(dirfd), symoldfilename, Some(dirfd), newfilename, LinkatFlags::SymlinkFollow).unwrap();
+
+    let newfilestat = stat::stat(&newfilepath).unwrap();
+
+    // Check the file type of the new link
+    assert!((stat::SFlag::from_bits_truncate(newfilestat.st_mode) & SFlag::S_IFMT) ==  SFlag::S_IFREG);
+
+    // Check the number of hard links to the original file
+    assert_eq!(newfilestat.st_nlink, 2);
+}
+
 #[test]
 fn test_unlinkat_dir_noremovedir() {
     let tempdir = tempfile::tempdir().unwrap();