diff --git a/node_darwin.go b/node_darwin.go
index 884c33d1c..38b3d1261 100644
--- a/node_darwin.go
+++ b/node_darwin.go
@@ -1,19 +1,68 @@
 package restic
 
-import "os"
+import (
+	"fmt"
+	"os"
+	"os/user"
+	"strconv"
+	"syscall"
+	"time"
+)
 
-func (node *Node) fill_extra(path string, fi os.FileInfo) error {
-	return nil
+func (node *Node) fill_extra(path string, fi os.FileInfo) (err error) {
+	stat, ok := fi.Sys().(*syscall.Stat_t)
+	if !ok {
+		return
+	}
+
+	node.ChangeTime = time.Unix(stat.Ctimespec.Unix())
+	node.AccessTime = time.Unix(stat.Atimespec.Unix())
+	node.UID = stat.Uid
+	node.GID = stat.Gid
+
+	// TODO: cache uid lookup
+	if u, nil := user.LookupId(strconv.Itoa(int(stat.Uid))); err == nil {
+		node.User = u.Username
+	}
+
+	// TODO: implement getgrnam() or use https://github.com/kless/osutil
+	// if g, nil := user.LookupId(strconv.Itoa(int(stat.Uid))); err == nil {
+	// 	node.User = u.Username
+	// }
+
+	node.Inode = stat.Ino
+
+	switch node.Type {
+	case "file":
+		node.Size = uint64(stat.Size)
+		node.Links = uint64(stat.Nlink)
+	case "dir":
+		// nothing to do
+	case "symlink":
+		node.LinkTarget, err = os.Readlink(path)
+	case "dev":
+		node.Device = uint64(stat.Rdev)
+	case "chardev":
+		node.Device = uint64(stat.Rdev)
+	case "fifo":
+		// nothing to do
+	case "socket":
+		// nothing to do
+	default:
+		panic(fmt.Sprintf("invalid node type %q", node.Type))
+	}
+
+	return err
 }
 
 func (node *Node) createDevAt(path string) error {
-	return nil
+	return syscall.Mknod(path, syscall.S_IFBLK|0600, int(node.Device))
 }
 
 func (node *Node) createCharDevAt(path string) error {
-	return nil
+	return syscall.Mknod(path, syscall.S_IFCHR|0600, int(node.Device))
 }
 
 func (node *Node) createFifoAt(path string) error {
-	return nil
+	return syscall.Mkfifo(path, 0600)
 }