diff --git a/util/fs.go b/util/fs.go
index f8f8eb1ee291fb64a02001e3c1828cadcf20bd00..11322e68ac9a139fd970e0e6f5fd016d10ec5e05 100644
--- a/util/fs.go
+++ b/util/fs.go
@@ -18,6 +18,7 @@ package util
 
 import (
   "fmt"
+  "io"
   "os"
 )
 
@@ -43,3 +44,66 @@ func IsDir(directory string) bool {
   }
   return fileInfo.IsDir()
 }
+
+// copied from http://stackoverflow.com/questions/21060945/simple-way-to-copy-a-file-in-golang
+// CopyFile copies a file from src to dst. If src and dst files exist, and are
+// the same, then return success. Otherise, attempt to create a hard link
+// between the two files. If that fail, copy the file contents from src to dst.
+func CopyFile(src, dst string) (err error) {
+    sfi, err := os.Stat(src)
+    if err != nil {
+        return
+    }
+    if !sfi.Mode().IsRegular() {
+        // cannot copy non-regular files (e.g., directories,
+        // symlinks, devices, etc.)
+        return fmt.Errorf("CopyFile: non-regular source file %s (%q)", sfi.Name(), sfi.Mode().String())
+    }
+    dfi, err := os.Stat(dst)
+    if err != nil {
+        if !os.IsNotExist(err) {
+            return
+        }
+    } else {
+        if !(dfi.Mode().IsRegular()) {
+            return fmt.Errorf("CopyFile: non-regular destination file %s (%q)", dfi.Name(), dfi.Mode().String())
+        }
+        if os.SameFile(sfi, dfi) {
+            return
+        }
+    }
+    // NOTE: [ben] we do not want to create a hard link currently
+    // if err = os.Link(src, dst); err == nil {
+    //     return
+    // }
+    err = copyFileContents(src, dst)
+    return
+}
+
+// copyFileContents copies the contents of the file named src to the file named
+// by dst. The file will be created if it does not already exist. If the
+// destination file exists, all its contents will be replaced by the contents
+// of the source file.
+func copyFileContents(src, dst string) (err error) {
+    in, err := os.Open(src)
+    if err != nil {
+        return
+    }
+    defer in.Close()
+    out, err := os.Create(dst)
+    if err != nil {
+        return
+    }
+    defer func() {
+        cerr := out.Close()
+        if err == nil {
+            err = cerr
+        }
+    }()
+    if _, err = io.Copy(out, in); err != nil {
+        return
+    }
+    // TODO: [ben] this blocks, so copy should be put in go-routine
+    err = out.Sync()
+    return
+}