From 046439a1ddec206706e368527f307492002dc18b Mon Sep 17 00:00:00 2001
From: Nico Schottelius <nico@brief.schottelius.org>
Date: Fri, 25 May 2012 10:38:15 +0200
Subject: [PATCH 01/29] +preos ideas

Signed-off-by: Nico Schottelius <nico@brief.schottelius.org>
---
 doc/dev/logs/2012-05-24.preos | 72 +++++++++++++++++++++++++++++++++++
 1 file changed, 72 insertions(+)
 create mode 100644 doc/dev/logs/2012-05-24.preos

diff --git a/doc/dev/logs/2012-05-24.preos b/doc/dev/logs/2012-05-24.preos
new file mode 100644
index 00000000..e4f988a7
--- /dev/null
+++ b/doc/dev/logs/2012-05-24.preos
@@ -0,0 +1,72 @@
+Todo for preos:
+
+get debian installer (?)
+    x86, amd64
+configure sshd
+    add authorized_keys
+output files
+    tftp: cuni:    curl -s "http://http.us.debian.org/debian/dists/$version/main/installer-$arch/current/images/netboot/netboot.tar.gz" | tar xz
+    iso
+
+
+http://wiki.debian.org/DebianInstaller/
+--------------------------------------------------------------------------------
+debootstrap:
+    [19:33] brief:hack% sudo debootstrap squeeze ./debian-squeeze
+    [19:30] brief:hack# du -sh .
+    213M    .
+
+install kernel
+    [19:35] brief:hack# chroot debian-squeeze/ apt-get -y install linux-image-amd64 
+    [19:37] brief:debian-squeeze# ls boot/initrd*                   
+    boot/initrd.img-2.6.32-5-amd64
+    [19:37] brief:debian-squeeze# ls boot/vmlinuz*
+    boot/vmlinuz-2.6.32-5-amd64
+
+install sshd
+    [19:37] brief:hack# chroot debian-squeeze/ apt-get -y --force-yes install openssh-server 
+
+    - connect back?
+    - generate sshd keys?
+
+--------------------------------------------------------------------------------
+initramfs:
+       find . -print0 | bsdcpio $( (( QUIET )) && echo '--quiet' ) -R 0:0 -0oH newc | $COMPRESSION $COMPRESSION_OPTIONS > "$IMGPATH"
+
+    /init for booting
+    find . -print0 | cpio --null -ov --format=newc | gzip -9 > /boot/my-initramfs.cpio.gz
+    cpio -H newc -o
+    find . | cpio -H newc -o > ../initramfs.cpio # <-- this is the actual initramfs
+
+
+[19:39] brief:debian-squeeze# find . | bsdcpio -H newc -o > ../initramfs.cpio 
+[19:43] brief:debian-squeeze# xz ../initramfs.cpio
+
+
+--------------------------------------------------------------------------------
+cdrom:
+    http://tldp.org/HOWTO/Bootdisk-HOWTO/cd-roms.html
+
+--------------------------------------------------------------------------------
+
+[19:34] brief:hack# chroot debian-squeeze/ apt-cache search kernel | grep linux-image
+linux-image-2.6.32-5-amd64-dbg - Debugging infos for Linux 2.6.32-5-amd64
+linux-image-2.6.32-5-amd64 - Linux 2.6.32 for 64-bit PCs
+linux-image-2.6.32-5-openvz-amd64-dbg - Debugging infos for Linux 2.6.32-5-openvz-amd64
+linux-image-2.6.32-5-openvz-amd64 - Linux 2.6.32 for 64-bit PCs, OpenVZ support
+linux-image-2.6.32-5-vserver-amd64-dbg - Debugging infos for Linux 2.6.32-5-vserver-amd64
+linux-image-2.6.32-5-vserver-amd64 - Linux 2.6.32 for 64-bit PCs, Linux-VServer support
+linux-image-2.6.32-5-xen-amd64-dbg - Debugging infos for Linux 2.6.32-5-xen-amd64
+linux-image-2.6.32-5-xen-amd64 - Linux 2.6.32 for 64-bit PCs, Xen dom0 support
+linux-image-2.6-amd64 - Linux 2.6 for 64-bit PCs (meta-package)
+linux-image-2.6-openvz-amd64 - Linux 2.6 for 64-bit PCs (meta-package), OpenVZ support
+linux-image-2.6-vserver-amd64 - Linux 2.6 for 64-bit PCs (meta-package), Linux-VServer support
+linux-image-2.6-xen-amd64 - Linux 2.6 for 64-bit PCs (meta-package), Xen dom0 support
+linux-image-amd64 - Linux for 64-bit PCs (meta-package)
+linux-image-openvz-amd64 - Linux for 64-bit PCs (meta-package), OpenVZ support
+linux-image-vserver-amd64 - Linux for 64-bit PCs (meta-package), Linux-VServer support
+linux-image-xen-amd64 - Linux for 64-bit PCs (meta-package), Xen dom0 support
+[19:34] brief:hack# 
+
+--------------------------------------------------------------------------------
+

From bba68b6e40c872b76450071aab5d22bb10c79e47 Mon Sep 17 00:00:00 2001
From: Steven Armstrong <steven@icarus.ethz.ch>
Date: Wed, 18 Sep 2013 10:40:29 +0200
Subject: [PATCH 02/29] only delete links; delete existing destination before
 creating links

Signed-off-by: Steven Armstrong <steven@icarus.ethz.ch>
---
 cdist/conf/type/__link/explorer/type          | 26 ++++++++++++++++
 cdist/conf/type/__link/gencode-remote         | 30 ++++++++++++++++---
 .../conf/type/__link/parameter/default/state  |  1 +
 3 files changed, 53 insertions(+), 4 deletions(-)
 create mode 100755 cdist/conf/type/__link/explorer/type
 create mode 100644 cdist/conf/type/__link/parameter/default/state

diff --git a/cdist/conf/type/__link/explorer/type b/cdist/conf/type/__link/explorer/type
new file mode 100755
index 00000000..c02b3af8
--- /dev/null
+++ b/cdist/conf/type/__link/explorer/type
@@ -0,0 +1,26 @@
+#!/bin/sh
+# 2013 Steven Armstrong (steven-cdist armstrong.cc)
+
+destination="/$__object_id"
+
+if [ ! -e "$destination" ]; then
+   echo none
+elif [ -h "$destination" ]; then
+   echo symlink
+elif [ -f "$destination" ]; then
+   type="$(cat "$__object/parameter/type")"
+   case "$type" in
+      hard)
+         link_count=$(ls -l "$destination" | awk '{ print $2 }')
+         if [ $link_count -gt 1 ]; then
+            echo hardlink
+            exit 0
+         fi
+      ;;
+   esac
+   echo file
+elif [ -d "$destination" ]; then
+   echo directory
+else
+   echo unknown
+fi
diff --git a/cdist/conf/type/__link/gencode-remote b/cdist/conf/type/__link/gencode-remote
index 2975ef69..2e41b7d9 100755
--- a/cdist/conf/type/__link/gencode-remote
+++ b/cdist/conf/type/__link/gencode-remote
@@ -1,6 +1,7 @@
 #!/bin/sh
 #
 # 2011-2012 Nico Schottelius (nico-cdist at schottelius.org)
+# 2013 Steven Armstrong (steven-cdist at armstrong.cc)
 #
 # This file is part of cdist.
 #
@@ -40,17 +41,38 @@ case "$type" in
 esac
 
 state_is="$(cat "$__object/explorer/state")"
-state_should=present
-[ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")"
+state_should="$(cat "$__object/parameter/state")"
 
 [ "$state_should" = "$state_is" ] && exit 0
 
+file_type="$(cat "$__object/explorer/type")"
 case "$state_should" in
     present)
-        echo ln ${lnopt} -f \"$source\" \"$destination\"
+        if [ "$file_type" = "directory" ]; then
+            # our destination is currently a directory, move it out of the way
+            cat << DONE
+destination_old="\$(mktemp "${destination}.cdist.XXXXXXXXXX")"
+mv "$destination" "\$destination_old"
+DONE
+        fi
+
+        # create our link
+        cat << DONE
+ln ${lnopt} -f "$source" "$destination"
+DONE
+
+        if [ "$file_type" = "directory" ]; then
+            # delete the legacy directory
+            cat << DONE
+rm -rf "\$destination_old"
+DONE
+        fi
     ;;
     absent)
-        echo rm -f \"$destination\"
+        # only delete if it is a sym/hard link
+        if [ "$file_type" = "symlink" -o "$file_type" = "hardlink" ]; then
+            echo rm -f \"$destination\"
+        fi
     ;;
     *)
         echo "Unknown state: $state_should" >&2
diff --git a/cdist/conf/type/__link/parameter/default/state b/cdist/conf/type/__link/parameter/default/state
new file mode 100644
index 00000000..e7f6134f
--- /dev/null
+++ b/cdist/conf/type/__link/parameter/default/state
@@ -0,0 +1 @@
+present

From 067614db1f15c5efcb330c0a417fab915595f724 Mon Sep 17 00:00:00 2001
From: Steven Armstrong <steven@icarus.ethz.ch>
Date: Wed, 18 Sep 2013 11:14:18 +0200
Subject: [PATCH 03/29] make explorers executable

Signed-off-by: Steven Armstrong <steven@icarus.ethz.ch>
---
 cdist/conf/type/__directory/explorer/group | 0
 cdist/conf/type/__directory/explorer/mode  | 0
 cdist/conf/type/__directory/explorer/owner | 0
 3 files changed, 0 insertions(+), 0 deletions(-)
 mode change 100644 => 100755 cdist/conf/type/__directory/explorer/group
 mode change 100644 => 100755 cdist/conf/type/__directory/explorer/mode
 mode change 100644 => 100755 cdist/conf/type/__directory/explorer/owner

diff --git a/cdist/conf/type/__directory/explorer/group b/cdist/conf/type/__directory/explorer/group
old mode 100644
new mode 100755
diff --git a/cdist/conf/type/__directory/explorer/mode b/cdist/conf/type/__directory/explorer/mode
old mode 100644
new mode 100755
diff --git a/cdist/conf/type/__directory/explorer/owner b/cdist/conf/type/__directory/explorer/owner
old mode 100644
new mode 100755

From 4bee421f9713569118ec22ac885703262871fdfa Mon Sep 17 00:00:00 2001
From: Steven Armstrong <steven@icarus.ethz.ch>
Date: Wed, 18 Sep 2013 13:25:45 +0200
Subject: [PATCH 04/29] rewrite type to work analog to __file and __link

Signed-off-by: Steven Armstrong <steven@icarus.ethz.ch>
---
 cdist/conf/type/__directory/explorer/group    |  39 ------
 cdist/conf/type/__directory/explorer/mode     |  39 ------
 cdist/conf/type/__directory/explorer/owner    |  39 ------
 cdist/conf/type/__directory/explorer/stat     |  26 ++++
 cdist/conf/type/__directory/explorer/state    |  30 -----
 cdist/conf/type/__directory/explorer/type     |  16 +++
 cdist/conf/type/__directory/gencode-remote    | 116 +++++++++++-------
 .../type/__directory/parameter/default/state  |   1 +
 8 files changed, 117 insertions(+), 189 deletions(-)
 delete mode 100755 cdist/conf/type/__directory/explorer/group
 delete mode 100755 cdist/conf/type/__directory/explorer/mode
 delete mode 100755 cdist/conf/type/__directory/explorer/owner
 create mode 100755 cdist/conf/type/__directory/explorer/stat
 delete mode 100755 cdist/conf/type/__directory/explorer/state
 create mode 100755 cdist/conf/type/__directory/explorer/type
 create mode 100644 cdist/conf/type/__directory/parameter/default/state

diff --git a/cdist/conf/type/__directory/explorer/group b/cdist/conf/type/__directory/explorer/group
deleted file mode 100755
index e5be37da..00000000
--- a/cdist/conf/type/__directory/explorer/group
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/bin/sh
-#
-# 2011 Nico Schottelius (nico-cdist at schottelius.org)
-#
-# This file is part of cdist.
-#
-# cdist is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# cdist is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with cdist. If not, see <http://www.gnu.org/licenses/>.
-#
-#
-# Check whether file exists or not
-#
-
-destination="/$__object_id"
-os=$("$__explorer/os")
-
-case "$os" in
-   "freebsd")
-      cmd="stat -f %Sg"
-      ;;
-   *)
-      cmd="stat -c %G"
-      ;;
-esac
-
-if [ -e "$destination" ]; then
-  $cmd "$destination"
-fi
-
diff --git a/cdist/conf/type/__directory/explorer/mode b/cdist/conf/type/__directory/explorer/mode
deleted file mode 100755
index f75b282b..00000000
--- a/cdist/conf/type/__directory/explorer/mode
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/bin/sh
-#
-# 2011 Nico Schottelius (nico-cdist at schottelius.org)
-#
-# This file is part of cdist.
-#
-# cdist is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# cdist is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with cdist. If not, see <http://www.gnu.org/licenses/>.
-#
-#
-# Check whether file exists or not
-#
-
-destination="/$__object_id"
-os=$("$__explorer/os")
-
-case "$os" in
-   "freebsd")
-      cmd="stat -f %Op"
-      ;;
-   *)
-      cmd="stat -c %a"
-      ;;
-esac
-
-if [ -e "$destination" ]; then
-  $cmd "$destination"
-fi
-
diff --git a/cdist/conf/type/__directory/explorer/owner b/cdist/conf/type/__directory/explorer/owner
deleted file mode 100755
index cebd199b..00000000
--- a/cdist/conf/type/__directory/explorer/owner
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/bin/sh
-#
-# 2011 Nico Schottelius (nico-cdist at schottelius.org)
-#
-# This file is part of cdist.
-#
-# cdist is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# cdist is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with cdist. If not, see <http://www.gnu.org/licenses/>.
-#
-#
-# Check whether file exists or not
-#
-
-destination="/$__object_id"
-os=$("$__explorer/os")
-
-case "$os" in
-   "freebsd")
-      cmd="stat -f %Su"
-      ;;  
-   *)  
-      cmd="stat -c %U"
-      ;;  
-esac
-
-if [ -e "$destination" ]; then
-  $cmd "$destination"
-fi
-
diff --git a/cdist/conf/type/__directory/explorer/stat b/cdist/conf/type/__directory/explorer/stat
new file mode 100755
index 00000000..2bd5d1c9
--- /dev/null
+++ b/cdist/conf/type/__directory/explorer/stat
@@ -0,0 +1,26 @@
+#!/bin/sh
+# 2013 Steven Armstrong (steven-cdist armstrong.cc)
+
+destination="/$__object_id"
+
+# nothing to work with, nothing we could do
+[ -e "$destination" ] || exit 0
+
+os=$("$__explorer/os")
+case "$os" in
+   "freebsd")
+      # FIXME: should be something like this based on man page, but can not test
+      stat -f "type: %ST
+owner: %Du %Su
+group: %Dg %Sg
+mode: %Op %Sp
+" "$destination"
+   ;;
+   *)
+      stat --printf="type: %F
+owner: %u %U
+group: %g %G
+mode: %a %A
+" "$destination"
+   ;;
+esac
diff --git a/cdist/conf/type/__directory/explorer/state b/cdist/conf/type/__directory/explorer/state
deleted file mode 100755
index 9bdd9024..00000000
--- a/cdist/conf/type/__directory/explorer/state
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/bin/sh
-#
-# 2011 Nico Schottelius (nico-cdist at schottelius.org)
-#
-# This file is part of cdist.
-#
-# cdist is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# cdist is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with cdist. If not, see <http://www.gnu.org/licenses/>.
-#
-#
-# Check whether file exists or not
-#
-
-destination="/$__object_id"
-
-if [ -e "$destination" ]; then
-   echo present
-else
-   echo absent
-fi
diff --git a/cdist/conf/type/__directory/explorer/type b/cdist/conf/type/__directory/explorer/type
new file mode 100755
index 00000000..6e6a2956
--- /dev/null
+++ b/cdist/conf/type/__directory/explorer/type
@@ -0,0 +1,16 @@
+#!/bin/sh
+# 2013 Steven Armstrong (steven-cdist armstrong.cc)
+
+destination="/$__object_id"
+
+if [ ! -e "$destination" ]; then
+   echo none
+elif [ -h "$destination" ]; then
+   echo symlink
+elif [ -f "$destination" ]; then
+   echo file
+elif [ -d "$destination" ]; then
+   echo directory
+else
+   echo unknown
+fi
diff --git a/cdist/conf/type/__directory/gencode-remote b/cdist/conf/type/__directory/gencode-remote
index f46a5967..ebe07318 100755
--- a/cdist/conf/type/__directory/gencode-remote
+++ b/cdist/conf/type/__directory/gencode-remote
@@ -1,6 +1,7 @@
 #!/bin/sh
 #
 # 2011-2012 Nico Schottelius (nico-cdist at schottelius.org)
+# 2013 Steven Armstrong (steven-cdist armstrong.cc)
 #
 # This file is part of cdist.
 #
@@ -19,53 +20,84 @@
 #
 
 destination="/$__object_id"
+state_should="$(cat "$__object/parameter/state")"
+type="$(cat "$__object/explorer/type")"
+stat_file="$__object/explorer/stat"
 
-state_is="$(cat "$__object/explorer/state")"
-owner_is="$(cat "$__object/explorer/owner")"
-group_is="$(cat "$__object/explorer/group")"
-mode_is="$(cat "$__object/explorer/mode")"
+# variable to keep track if we have to set directory attributes
+set_attributes=
 
-state_should="present"
-[ -f "$__object/parameter/state" ]     && state_should="$(cat "$__object/parameter/state")"
-mode=""
-[ -f "$__object/parameter/mode" ]      && mode="$(cat "$__object/parameter/mode")"
-owner=""
-[ -f "$__object/parameter/owner" ]     && owner="$(cat "$__object/parameter/owner")"
-group=""
-[ -f "$__object/parameter/group" ]     && group="$(cat "$__object/parameter/group")"
 mkdiropt=""
-[ -f "$__object/parameter/parents" ]   && mkdiropt="-p"
+[ -f "$__object/parameter/parents" ] && mkdiropt="-p"
+
 recursive=""
-[ -f "$__object/parameter/recursive" ] && recursive="-R"
+if [ -f "$__object/parameter/recursive" ]; then
+   recursive="-R"
+   # need to allways set attributes when recursive is given
+   # as we don't want to check all subfolders/files
+   set_attributes=1
+fi
+
+get_current_value() {
+   if [ -s "$stat_file" ]; then
+      _name="$1"
+      _value="$2"
+      case "$_value" in
+         [0-9]*)
+            _index=2
+         ;;
+         *)
+            _index=3
+         ;;
+      esac
+      awk '/'"$_name"':/ { print $'$_index' }' "$stat_file"
+      unset _name _value _index
+   fi
+}
+
+set_group() {
+   echo chgrp $recursive \"$1\" \"$destination\"
+}
+
+set_owner() {
+   echo chown $recursive \"$1\" \"$destination\"
+}
+
+set_mode() {
+   echo chmod $recursive \"$1\" \"$destination\"
+}
 
 case "$state_should" in
-    present)
-        if [ "$state_is" != "present" ]; then
-            echo mkdir $mkdiropt \"$destination\"
-        fi
+   present)
+      if [ "$type" != "directory" ];
+         # our destination is not a directory, remove whatever is there
+         # and then create our directory and set all attributes
+         set_attributes=1
+         cat << DONE
+rm -f "$destination"
+mkdir "$mkdiropt" "$destination"
+DONE
+      fi
 
-        # Mode settings
-        if [ "$mode" ] && [ "$mode_is" != "$mode" -o -n "$recursive" ]; then
-            echo chmod $recursive \"$mode\" \"$destination\"
-        fi
-
-        # Group
-        if [ "$group" ] && [ "$group_is" != "$group" -o -n "$recursive" ]; then
-            echo chgrp $recursive \"$group\" \"$destination\"
-        fi
-
-        # Owner
-        if [ "$owner" ] && [ "$owner_is" != "$owner" -o -n "$recursive" ]; then
-            echo chown $recursive \"$owner\" \"$destination\"
-        fi
-    ;;
-    absent)
-        if [ "$state_is" != "absent" ]; then
-          echo rm -rf \"$destination\"
-        fi
-    ;;
-    *)
-        echo "Unknown state: $state_should" >&2
-        exit 1
-    ;;
+      # Note: Mode - needs to happen last as a chown/chgrp can alter mode by
+      # clearing S_ISUID and S_ISGID bits (see chown(2))
+      for attribute in group owner mode; do
+         if [ -f "$__object/parameter/$attribute" ]; then
+            value_should="$(cat "$__object/parameter/$attribute")"
+            value_is="$(get_current_value "$attribute" "$value_should")"
+            if [ "$set_attributes" -o "$value_should" != "$value_is" ]; then
+               "set_$attribute" "$value_should"
+            fi
+         fi
+      done
+   ;;
+   absent)
+      if [ "$type" = "directory" ]; then
+         echo rm -rf \"$destination\"
+      fi
+   ;;
+   *)
+      echo "Unknown state: $state_should" >&2
+      exit 1
+   ;;
 esac
diff --git a/cdist/conf/type/__directory/parameter/default/state b/cdist/conf/type/__directory/parameter/default/state
new file mode 100644
index 00000000..e7f6134f
--- /dev/null
+++ b/cdist/conf/type/__directory/parameter/default/state
@@ -0,0 +1 @@
+present

From 9db28fab97083364f2c9e96cd15a136136c9d6b1 Mon Sep 17 00:00:00 2001
From: Steven Armstrong <steven@icarus.ethz.ch>
Date: Tue, 15 Oct 2013 14:55:35 +0200
Subject: [PATCH 05/29] no late delete

Signed-off-by: Steven Armstrong <steven@icarus.ethz.ch>
---
 cdist/conf/type/__link/gencode-remote | 12 ++----------
 1 file changed, 2 insertions(+), 10 deletions(-)

diff --git a/cdist/conf/type/__link/gencode-remote b/cdist/conf/type/__link/gencode-remote
index 2e41b7d9..cbdfd30f 100755
--- a/cdist/conf/type/__link/gencode-remote
+++ b/cdist/conf/type/__link/gencode-remote
@@ -49,10 +49,9 @@ file_type="$(cat "$__object/explorer/type")"
 case "$state_should" in
     present)
         if [ "$file_type" = "directory" ]; then
-            # our destination is currently a directory, move it out of the way
+            # our destination is currently a directory, delete it
             cat << DONE
-destination_old="\$(mktemp "${destination}.cdist.XXXXXXXXXX")"
-mv "$destination" "\$destination_old"
+rm -rf "$destination"
 DONE
         fi
 
@@ -60,13 +59,6 @@ DONE
         cat << DONE
 ln ${lnopt} -f "$source" "$destination"
 DONE
-
-        if [ "$file_type" = "directory" ]; then
-            # delete the legacy directory
-            cat << DONE
-rm -rf "\$destination_old"
-DONE
-        fi
     ;;
     absent)
         # only delete if it is a sym/hard link

From db29ea8e7020b0850671aac9b8e9e142e7b0e960 Mon Sep 17 00:00:00 2001
From: Steven Armstrong <steven@icarus.ethz.ch>
Date: Thu, 12 Sep 2013 14:02:33 +0200
Subject: [PATCH 06/29] intial take on fixing the file type

- upload file in a safer way
- remove destination if it is not a file
- only set attributes if required

Signed-off-by: Steven Armstrong <steven@icarus.ethz.ch>
---
 cdist/conf/type/__file/explorer/exists        | 30 ------
 cdist/conf/type/__file/explorer/stat          | 30 ++++++
 cdist/conf/type/__file/explorer/type          | 16 ++++
 cdist/conf/type/__file/gencode-local          | 47 ++++++----
 cdist/conf/type/__file/gencode-remote         | 93 +++++++++++++------
 cdist/conf/type/__file/man.text               |  9 ++
 .../conf/type/__file/parameter/default/state  |  1 +
 7 files changed, 150 insertions(+), 76 deletions(-)
 delete mode 100755 cdist/conf/type/__file/explorer/exists
 create mode 100755 cdist/conf/type/__file/explorer/stat
 create mode 100755 cdist/conf/type/__file/explorer/type
 create mode 100644 cdist/conf/type/__file/parameter/default/state

diff --git a/cdist/conf/type/__file/explorer/exists b/cdist/conf/type/__file/explorer/exists
deleted file mode 100755
index c319cb5d..00000000
--- a/cdist/conf/type/__file/explorer/exists
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/bin/sh
-#
-# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org)
-#
-# This file is part of cdist.
-#
-# cdist is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# cdist is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with cdist. If not, see <http://www.gnu.org/licenses/>.
-#
-#
-# Check whether file exists or not
-#
-
-destination="/$__object_id"
-
-if [ -e "$destination" ]; then
-    echo yes
-else
-    echo no
-fi
diff --git a/cdist/conf/type/__file/explorer/stat b/cdist/conf/type/__file/explorer/stat
new file mode 100755
index 00000000..40a00aba
--- /dev/null
+++ b/cdist/conf/type/__file/explorer/stat
@@ -0,0 +1,30 @@
+#!/bin/sh
+# 2013 Steven Armstrong (steven-cdist armstrong.cc)
+
+destination="/$__object_id"
+
+# nothing to work with, nothing we could do
+[ -e "$destination" ] || exit 0
+
+os=$("$__explorer/os")
+case "$os" in
+   "freebsd")
+      # FIXME: should be something like this based on man page, but can not test
+      stat -f "type: %ST
+owner: %Du %Su
+group: %Dg %Sg
+mode: %Op %Sp
+size: %Dz
+links: %Dl
+" "$destination"
+   ;;
+   *)
+      stat --printf="type: %F
+owner: %u %U
+group: %g %G
+mode: %a %A
+size: %s
+links: %h
+" "$destination"
+   ;;
+esac
diff --git a/cdist/conf/type/__file/explorer/type b/cdist/conf/type/__file/explorer/type
new file mode 100755
index 00000000..6e6a2956
--- /dev/null
+++ b/cdist/conf/type/__file/explorer/type
@@ -0,0 +1,16 @@
+#!/bin/sh
+# 2013 Steven Armstrong (steven-cdist armstrong.cc)
+
+destination="/$__object_id"
+
+if [ ! -e "$destination" ]; then
+   echo none
+elif [ -h "$destination" ]; then
+   echo symlink
+elif [ -f "$destination" ]; then
+   echo file
+elif [ -d "$destination" ]; then
+   echo directory
+else
+   echo unknown
+fi
diff --git a/cdist/conf/type/__file/gencode-local b/cdist/conf/type/__file/gencode-local
index 087011c4..80a2bc20 100755
--- a/cdist/conf/type/__file/gencode-local
+++ b/cdist/conf/type/__file/gencode-local
@@ -1,6 +1,7 @@
 #!/bin/sh
 #
 # 2011-2012 Nico Schottelius (nico-cdist at schottelius.org)
+# 2013 Steven Armstrong (steven-cdist armstrong.cc)
 #
 # This file is part of cdist.
 #
@@ -17,34 +18,46 @@
 # You should have received a copy of the GNU General Public License
 # along with cdist. If not, see <http://www.gnu.org/licenses/>.
 #
-#
-# __file is a very basic type, which will probably be reused quite often
-#
 
 destination="/$__object_id"
-state_should=present
-[ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")"
-exists="$(cat "$__object/explorer/exists")"
+state_should="$(cat "$__object/parameter/state")"
+type="$(cat "$__object/explorer/type")"
 
-[ "$state_should" = "exists" -a "$exists" = "yes" ] && exit 0 # nothing to do
+[ "$state_should" = "exists" -a "$type" = "file" ] && exit 0 # nothing to do
 
+upload_file=
+create_file=
 if [ "$state_should" = "present" -o "$state_should" = "exists" ]; then
-   if [ -f "$__object/parameter/source" ]; then
+   if [ ! -f "$__object/parameter/source" ]; then
+      create_file=1
+   else
       source="$(cat "$__object/parameter/source")"
       if [ "$source" = "-" ]; then
          source="$__object/stdin"
       fi
-
-      if [ -f "$source" ]; then
-         local_cksum="$(cksum < "$source")"
-         remote_cksum="$(cat "$__object/explorer/cksum")"
-
-         if [ "$local_cksum" != "$remote_cksum" ]; then
-            echo "$__remote_copy" "$source" "${__target_host}:${destination}"
-         fi
-      else
+      if [ ! -f "$source" ]; then
          echo "Source \"$source\" does not exist." >&2
          exit 1
+      else
+         if [ "$type" != "file" ]; then
+            # destination is not a regular file, upload source to replace it
+            upload_file=1
+         else
+            local_cksum="$(cksum < "$source")"
+            remote_cksum="$(cat "$__object/explorer/cksum")"
+            if [ "$local_cksum" != "$remote_cksum" ]; then
+               # destination is a regular file, but not the right one
+               upload_file=1
+            fi
+         fi
+      fi
+   fi
+   if [ "$create_file" -o "$upload_file" ]; then
+      mkdir "$__object/files"
+      tempfile_template="${destination}.cdist.XXXXXXXXXX"
+      echo "$__remote_exec ${__target_host} \"mktemp $tempfile_template\" > \"$__object/files/destination_upload\""
+      if [ "$upload_file" ]; then
+         echo "$__remote_copy $source ${__target_host}:\$(cat \"$__object/files/destination_upload\")"
       fi
    fi
 fi
diff --git a/cdist/conf/type/__file/gencode-remote b/cdist/conf/type/__file/gencode-remote
index 8b03e919..b0f7757f 100755
--- a/cdist/conf/type/__file/gencode-remote
+++ b/cdist/conf/type/__file/gencode-remote
@@ -1,6 +1,7 @@
 #!/bin/sh
 #
 # 2011-2012 Nico Schottelius (nico-cdist at schottelius.org)
+# 2013 Steven Armstrong (steven-cdist armstrong.cc)
 #
 # This file is part of cdist.
 #
@@ -17,52 +18,86 @@
 # You should have received a copy of the GNU General Public License
 # along with cdist. If not, see <http://www.gnu.org/licenses/>.
 #
-#
-# __file is a very basic type, which will probably be reused quite often
-#
 
 destination="/$__object_id"
-state_should=present
-[ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")"
-exists="$(cat "$__object/explorer/exists")"
+state_should="$(cat "$__object/parameter/state")"
+type="$(cat "$__object/explorer/type")"
+stat_file="$__object/explorer/stat"
 
+
+get_current_value() {
+   if [ -s "$stat_file" ]; then
+      _name="$1"
+      _value="$2"
+      case "$_value" in
+         [0-9]*)
+            _index=2
+         ;;
+         *)
+            _index=3
+         ;;
+      esac
+      awk '/'"$_name"':/ { print $'$_index' }' "$stat_file"
+      unset _name _value _index
+   fi
+}
+
+set_group() {
+   echo chgrp \"$1\" \"$destination\"
+}
+
+set_owner() {
+   echo chown \"$1\" \"$destination\"
+}
+
+set_mode() {
+   echo chmod \"$1\" \"$destination\"
+}
+
+set_attributes=
 case "$state_should" in
    present|exists)
-      # No source? Create empty file
-      if [ ! -f "$__object/parameter/source" ]; then
-         if [ "$exists" = "no" ]; then
-            echo touch \"$destination\"
+      if [ -f "$__object/files/destination_upload" ]; then
+         # we uploaded a file, move it into place and set all attributes
+         destination_upload="$(cat "$__object/files/destination_upload")"
+         set_attributes=1
+         if [ "$type" = "directory" ]; then
+            # our destination is currently a directory, move it out of the way,
+            # then delete it after moving our upload into place
+            cat << DONE
+destination_old="\$(mktemp "${destination}.cdist.XXXXXXXXXX")"
+mv "$destination" "$destination_old"
+mv "$destination_upload" "$destination"
+rm -rf "$destination_old"
+DONE
+         else
+            # move our upload into place
+            echo "mv \"$destination_upload\" \"$destination\""
          fi
       fi
 
-      # Group
-      if [ -f "$__object/parameter/group" ]; then
-         echo chgrp \"$(cat "$__object/parameter/group")\" \"$destination\"
-      fi
-
-      # Owner
-      if [ -f "$__object/parameter/owner" ]; then
-         echo chown \"$(cat "$__object/parameter/owner")\" \"$destination\"
-      fi
-
-      # Mode - needs to happen last as a chown/chgrp can alter mode by
-      # clearing S_ISUID and S_ISGID bits (see chown(2))
-      if [ -f "$__object/parameter/mode" ]; then
-         echo chmod \"$(cat "$__object/parameter/mode")\" \"$destination\"
-      fi
+      # Note: Mode - needs to happen last as a chown/chgrp can alter mode by
+      #  clearing S_ISUID and S_ISGID bits (see chown(2))
+      for attribute in group owner mode; do
+         if [ -f "$__object/parameter/$attribute" ]; then
+            value_should="$(cat "$__object/parameter/$attribute")"
+            value_is="$(get_current_value "$attribute" "$value_should")"
+            if [ "$set_attributes" -o "$value_should" != "$value_is" ]; then
+               "set_$attribute" "$value_should"
+            fi
+         fi
+      done
    ;;
 
    absent)
-
-      if [ "$exists" = "yes" ]; then
+      # FIXME: only delete if it's a file? or no matter what?
+      if [ "$type" = "file" ]; then
          echo rm -f \"$destination\"
       fi
-
    ;;
 
    *)
       echo "Unknown state: $state_should" >&2
       exit 1
    ;;
-
 esac
diff --git a/cdist/conf/type/__file/man.text b/cdist/conf/type/__file/man.text
index 1c61fd51..7cbde0ce 100644
--- a/cdist/conf/type/__file/man.text
+++ b/cdist/conf/type/__file/man.text
@@ -13,6 +13,15 @@ DESCRIPTION
 This cdist type allows you to create files, remove files and set file
 attributes on the target.
 
+If the file already exists on the target, then if it is a:
+- regular file, and state is:
+   present: replace it with the source file if they are not equal
+   exists: do nothing
+- symlink: replace it with the source file
+- directory: replace it with the source file
+
+In any case, make sure that the file attributes are as specified.
+
 
 REQUIRED PARAMETERS
 -------------------
diff --git a/cdist/conf/type/__file/parameter/default/state b/cdist/conf/type/__file/parameter/default/state
new file mode 100644
index 00000000..e7f6134f
--- /dev/null
+++ b/cdist/conf/type/__file/parameter/default/state
@@ -0,0 +1 @@
+present

From 12ef3ca4d2766fae030790a52b6dff189dcc85dc Mon Sep 17 00:00:00 2001
From: Steven Armstrong <steven@icarus.ethz.ch>
Date: Thu, 12 Sep 2013 16:16:18 +0200
Subject: [PATCH 07/29] first generate and execute *-local, then *-remote

Signed-off-by: Steven Armstrong <steven@icarus.ethz.ch>
---
 cdist/config.py | 28 +++++++++++++++++-----------
 1 file changed, 17 insertions(+), 11 deletions(-)

diff --git a/cdist/config.py b/cdist/config.py
index 7e003835..89f3e325 100644
--- a/cdist/config.py
+++ b/cdist/config.py
@@ -248,23 +248,29 @@ class Config(object):
 
         cdist_type = cdist_object.cdist_type
 
-        # Generate
         self.log.info("Generating and executing code for %s" % (cdist_object.name))
-        cdist_object.code_local = self.code.run_gencode_local(cdist_object)
-        cdist_object.code_remote = self.code.run_gencode_remote(cdist_object)
-        if cdist_object.code_local or cdist_object.code_remote:
-            cdist_object.changed = True
 
-        # Execute
-        if not self.dry_run:
-            if cdist_object.code_local:
+        # local
+        cdist_object.code_local = self.code.run_gencode_local(cdist_object)
+        if cdist_object.code_local:
+            cdist_object.changed = True
+            if not self.dry_run:
                 self.code.run_code_local(cdist_object)
-            if cdist_object.code_remote:
+            else:
+                self.log.info("Skipping code execution due to DRY RUN")
+
+        # remote
+        cdist_object.code_remote = self.code.run_gencode_remote(cdist_object)
+        if cdist_object.code_remote:
+            cdist_object.changed = True
+            if not self.dry_run:
                 self.code.transfer_code_remote(cdist_object)
                 self.code.run_code_remote(cdist_object)
-        else:
-            self.log.info("Skipping code execution due to DRY RUN")
+            else:
+                self.log.info("Skipping code execution due to DRY RUN")
 
+        if cdist_object.code_local or cdist_object.code_remote:
+            cdist_object.changed = True
 
         # Mark this object as done
         self.log.debug("Finishing run of " + cdist_object.name)

From 5918de368d7541c051a83c340143f332f94e7631 Mon Sep 17 00:00:00 2001
From: Steven Armstrong <steven@icarus.ethz.ch>
Date: Wed, 18 Sep 2013 10:44:52 +0200
Subject: [PATCH 08/29] fix quoting, remove redundant code

Signed-off-by: Steven Armstrong <steven@icarus.ethz.ch>
---
 cdist/conf/type/__file/gencode-remote | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/cdist/conf/type/__file/gencode-remote b/cdist/conf/type/__file/gencode-remote
index b0f7757f..09f8e018 100755
--- a/cdist/conf/type/__file/gencode-remote
+++ b/cdist/conf/type/__file/gencode-remote
@@ -63,16 +63,22 @@ case "$state_should" in
          set_attributes=1
          if [ "$type" = "directory" ]; then
             # our destination is currently a directory, move it out of the way,
-            # then delete it after moving our upload into place
             cat << DONE
 destination_old="\$(mktemp "${destination}.cdist.XXXXXXXXXX")"
-mv "$destination" "$destination_old"
-mv "$destination_upload" "$destination"
-rm -rf "$destination_old"
+mv "$destination" "\$destination_old"
+DONE
+         fi
+
+         # move our upload into place
+         cat << DONE
+mv "$destination_upload" "$destination"
+DONE
+
+         if [ "$type" = "directory" ]; then
+            # delete the legacy directory
+            cat << DONE
+rm -rf "\$destination_old"
 DONE
-         else
-            # move our upload into place
-            echo "mv \"$destination_upload\" \"$destination\""
          fi
       fi
 

From f82c4dc6694bf63fc1fcb868126b28c855ca108e Mon Sep 17 00:00:00 2001
From: Steven Armstrong <steven@icarus.ethz.ch>
Date: Mon, 14 Oct 2013 21:17:59 +0200
Subject: [PATCH 09/29] no late delete

Signed-off-by: Steven Armstrong <steven@icarus.ethz.ch>
---
 cdist/conf/type/__file/gencode-remote | 14 ++------------
 1 file changed, 2 insertions(+), 12 deletions(-)

diff --git a/cdist/conf/type/__file/gencode-remote b/cdist/conf/type/__file/gencode-remote
index 09f8e018..2e7ca633 100755
--- a/cdist/conf/type/__file/gencode-remote
+++ b/cdist/conf/type/__file/gencode-remote
@@ -62,24 +62,15 @@ case "$state_should" in
          destination_upload="$(cat "$__object/files/destination_upload")"
          set_attributes=1
          if [ "$type" = "directory" ]; then
-            # our destination is currently a directory, move it out of the way,
+            # our destination is currently a directory, delete it
             cat << DONE
-destination_old="\$(mktemp "${destination}.cdist.XXXXXXXXXX")"
-mv "$destination" "\$destination_old"
+rm -rf "$destination"
 DONE
          fi
-
          # move our upload into place
          cat << DONE
 mv "$destination_upload" "$destination"
 DONE
-
-         if [ "$type" = "directory" ]; then
-            # delete the legacy directory
-            cat << DONE
-rm -rf "\$destination_old"
-DONE
-         fi
       fi
 
       # Note: Mode - needs to happen last as a chown/chgrp can alter mode by
@@ -96,7 +87,6 @@ DONE
    ;;
 
    absent)
-      # FIXME: only delete if it's a file? or no matter what?
       if [ "$type" = "file" ]; then
          echo rm -f \"$destination\"
       fi

From a3dea70a97e60917f1e2f124985f7b77a0193feb Mon Sep 17 00:00:00 2001
From: Steven Armstrong <steven@icarus.ethz.ch>
Date: Tue, 26 Nov 2013 16:14:44 +0100
Subject: [PATCH 10/29] Revert "first generate and execute *-local, then
 *-remote"

This reverts commit cf22499538266b1b4fac1694254edfd8ba9be68d.
---
 cdist/config.py | 30 ++++++++++++------------------
 1 file changed, 12 insertions(+), 18 deletions(-)

diff --git a/cdist/config.py b/cdist/config.py
index 89f3e325..7e003835 100644
--- a/cdist/config.py
+++ b/cdist/config.py
@@ -248,30 +248,24 @@ class Config(object):
 
         cdist_type = cdist_object.cdist_type
 
+        # Generate
         self.log.info("Generating and executing code for %s" % (cdist_object.name))
-
-        # local
         cdist_object.code_local = self.code.run_gencode_local(cdist_object)
-        if cdist_object.code_local:
-            cdist_object.changed = True
-            if not self.dry_run:
-                self.code.run_code_local(cdist_object)
-            else:
-                self.log.info("Skipping code execution due to DRY RUN")
-
-        # remote
         cdist_object.code_remote = self.code.run_gencode_remote(cdist_object)
-        if cdist_object.code_remote:
-            cdist_object.changed = True
-            if not self.dry_run:
-                self.code.transfer_code_remote(cdist_object)
-                self.code.run_code_remote(cdist_object)
-            else:
-                self.log.info("Skipping code execution due to DRY RUN")
-
         if cdist_object.code_local or cdist_object.code_remote:
             cdist_object.changed = True
 
+        # Execute
+        if not self.dry_run:
+            if cdist_object.code_local:
+                self.code.run_code_local(cdist_object)
+            if cdist_object.code_remote:
+                self.code.transfer_code_remote(cdist_object)
+                self.code.run_code_remote(cdist_object)
+        else:
+            self.log.info("Skipping code execution due to DRY RUN")
+
+
         # Mark this object as done
         self.log.debug("Finishing run of " + cdist_object.name)
         cdist_object.state = core.CdistObject.STATE_DONE

From fcfd2d0a3c6410f73b73cd897f5dd09526868f35 Mon Sep 17 00:00:00 2001
From: Steven Armstrong <steven@icarus.ethz.ch>
Date: Tue, 26 Nov 2013 16:30:03 +0100
Subject: [PATCH 11/29] refactor so that there is no interaction between
 code-local and code-remote

Signed-off-by: Steven Armstrong <steven@icarus.ethz.ch>
---
 cdist/conf/type/__file/gencode-local  | 17 +++++++++++++++--
 cdist/conf/type/__file/gencode-remote | 18 +-----------------
 cdist/config.py                       |  4 +++-
 3 files changed, 19 insertions(+), 20 deletions(-)

diff --git a/cdist/conf/type/__file/gencode-local b/cdist/conf/type/__file/gencode-local
index 80a2bc20..a9eb6b10 100755
--- a/cdist/conf/type/__file/gencode-local
+++ b/cdist/conf/type/__file/gencode-local
@@ -53,11 +53,24 @@ if [ "$state_should" = "present" -o "$state_should" = "exists" ]; then
       fi
    fi
    if [ "$create_file" -o "$upload_file" ]; then
+      # tell gencode-remote that we created or uploaded a file and that it must
+      # set all attributes no matter what the explorer retreived
       mkdir "$__object/files"
+      touch "$__object/files/set-attributes"
+
+      # upload file to temp location
       tempfile_template="${destination}.cdist.XXXXXXXXXX"
-      echo "$__remote_exec ${__target_host} \"mktemp $tempfile_template\" > \"$__object/files/destination_upload\""
+      cat << DONE
+destination_upload="\$($__remote_exec $__target_host "mktemp $tempfile_template")"
+DONE
       if [ "$upload_file" ]; then
-         echo "$__remote_copy $source ${__target_host}:\$(cat \"$__object/files/destination_upload\")"
+         cat << DONE
+$__remote_copy $source ${__target_host}:\$destination_upload
+DONE
       fi
+# move uploaded file into place
+cat << DONE
+$__remote_exec $__target_host "rm -rf \"$destination\"; mv \"\$destination_upload\" \"$destination\""
+DONE
    fi
 fi
diff --git a/cdist/conf/type/__file/gencode-remote b/cdist/conf/type/__file/gencode-remote
index 2e7ca633..e80d5fae 100755
--- a/cdist/conf/type/__file/gencode-remote
+++ b/cdist/conf/type/__file/gencode-remote
@@ -57,29 +57,13 @@ set_mode() {
 set_attributes=
 case "$state_should" in
    present|exists)
-      if [ -f "$__object/files/destination_upload" ]; then
-         # we uploaded a file, move it into place and set all attributes
-         destination_upload="$(cat "$__object/files/destination_upload")"
-         set_attributes=1
-         if [ "$type" = "directory" ]; then
-            # our destination is currently a directory, delete it
-            cat << DONE
-rm -rf "$destination"
-DONE
-         fi
-         # move our upload into place
-         cat << DONE
-mv "$destination_upload" "$destination"
-DONE
-      fi
-
       # Note: Mode - needs to happen last as a chown/chgrp can alter mode by
       #  clearing S_ISUID and S_ISGID bits (see chown(2))
       for attribute in group owner mode; do
          if [ -f "$__object/parameter/$attribute" ]; then
             value_should="$(cat "$__object/parameter/$attribute")"
             value_is="$(get_current_value "$attribute" "$value_should")"
-            if [ "$set_attributes" -o "$value_should" != "$value_is" ]; then
+            if [ -f "$__object/files/set-attributes" -o "$value_should" != "$value_is" ]; then
                "set_$attribute" "$value_should"
             fi
          fi
diff --git a/cdist/config.py b/cdist/config.py
index 7e003835..3f8a7fc6 100644
--- a/cdist/config.py
+++ b/cdist/config.py
@@ -249,7 +249,7 @@ class Config(object):
         cdist_type = cdist_object.cdist_type
 
         # Generate
-        self.log.info("Generating and executing code for %s" % (cdist_object.name))
+        self.log.info("Generating code for %s" % (cdist_object.name))
         cdist_object.code_local = self.code.run_gencode_local(cdist_object)
         cdist_object.code_remote = self.code.run_gencode_remote(cdist_object)
         if cdist_object.code_local or cdist_object.code_remote:
@@ -257,6 +257,8 @@ class Config(object):
 
         # Execute
         if not self.dry_run:
+            if cdist_object.code_local or cdist_object.code_remote:
+                self.log.info("Executing code for %s" % (cdist_object.name))
             if cdist_object.code_local:
                 self.code.run_code_local(cdist_object)
             if cdist_object.code_remote:

From dc27a15ec026ae8d4eeb73ae50c3931e2917bbe6 Mon Sep 17 00:00:00 2001
From: Nico Schottelius <nico@bento.schottelius.org>
Date: Wed, 27 Nov 2013 15:10:06 +0100
Subject: [PATCH 12/29] ++changes(2.3.7)

Signed-off-by: Nico Schottelius <nico@bento.schottelius.org>
---
 docs/changelog | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/docs/changelog b/docs/changelog
index e7d90609..7dfaefb2 100644
--- a/docs/changelog
+++ b/docs/changelog
@@ -4,6 +4,9 @@ Changelog
 	* Changes are always commented with their author in (braces)
 	* Exception: No braces means author == Nico Schottelius
 
+2.3.7:
+	* Type __file: Secure the file transfer by using mktemp (Steven Armstrong)
+
 2.3.6: 2013-11-25
 	* New Type: __locale
 	* Type __line: Ensure special characters are not interpreted

From 6c3b1e3ca0369e9e46e9088467efe7d7d875f178 Mon Sep 17 00:00:00 2001
From: Steven Armstrong <steven@icarus.ethz.ch>
Date: Wed, 27 Nov 2013 16:05:10 +0100
Subject: [PATCH 13/29] add gpl header

Signed-off-by: Steven Armstrong <steven@icarus.ethz.ch>
---
 cdist/conf/type/__file/explorer/stat | 17 +++++++++++++++++
 cdist/conf/type/__file/explorer/type | 17 +++++++++++++++++
 2 files changed, 34 insertions(+)

diff --git a/cdist/conf/type/__file/explorer/stat b/cdist/conf/type/__file/explorer/stat
index 40a00aba..298221b7 100755
--- a/cdist/conf/type/__file/explorer/stat
+++ b/cdist/conf/type/__file/explorer/stat
@@ -1,5 +1,22 @@
 #!/bin/sh
+#
 # 2013 Steven Armstrong (steven-cdist armstrong.cc)
+#
+# This file is part of cdist.
+#
+# cdist is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# cdist is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with cdist. If not, see <http://www.gnu.org/licenses/>.
+#
 
 destination="/$__object_id"
 
diff --git a/cdist/conf/type/__file/explorer/type b/cdist/conf/type/__file/explorer/type
index 6e6a2956..e723047c 100755
--- a/cdist/conf/type/__file/explorer/type
+++ b/cdist/conf/type/__file/explorer/type
@@ -1,5 +1,22 @@
 #!/bin/sh
+#
 # 2013 Steven Armstrong (steven-cdist armstrong.cc)
+#
+# This file is part of cdist.
+#
+# cdist is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# cdist is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with cdist. If not, see <http://www.gnu.org/licenses/>.
+#
 
 destination="/$__object_id"
 

From d7984df503a888b3ab889ac4aaaa0993e5dbfee4 Mon Sep 17 00:00:00 2001
From: Steven Armstrong <steven@icarus.ethz.ch>
Date: Wed, 18 Sep 2013 11:14:18 +0200
Subject: [PATCH 14/29] make explorers executable

Signed-off-by: Steven Armstrong <steven@icarus.ethz.ch>
---
 cdist/conf/type/__directory/explorer/group | 0
 cdist/conf/type/__directory/explorer/mode  | 0
 cdist/conf/type/__directory/explorer/owner | 0
 3 files changed, 0 insertions(+), 0 deletions(-)
 mode change 100644 => 100755 cdist/conf/type/__directory/explorer/group
 mode change 100644 => 100755 cdist/conf/type/__directory/explorer/mode
 mode change 100644 => 100755 cdist/conf/type/__directory/explorer/owner

diff --git a/cdist/conf/type/__directory/explorer/group b/cdist/conf/type/__directory/explorer/group
old mode 100644
new mode 100755
diff --git a/cdist/conf/type/__directory/explorer/mode b/cdist/conf/type/__directory/explorer/mode
old mode 100644
new mode 100755
diff --git a/cdist/conf/type/__directory/explorer/owner b/cdist/conf/type/__directory/explorer/owner
old mode 100644
new mode 100755

From 7b065e931f78d9b0031a407fa4b364ea7af3b180 Mon Sep 17 00:00:00 2001
From: Steven Armstrong <steven@icarus.ethz.ch>
Date: Wed, 18 Sep 2013 13:25:45 +0200
Subject: [PATCH 15/29] rewrite type to work analog to __file and __link

Signed-off-by: Steven Armstrong <steven@icarus.ethz.ch>
---
 cdist/conf/type/__directory/explorer/group    |  39 ------
 cdist/conf/type/__directory/explorer/mode     |  39 ------
 cdist/conf/type/__directory/explorer/owner    |  39 ------
 cdist/conf/type/__directory/explorer/stat     |  26 ++++
 cdist/conf/type/__directory/explorer/state    |  30 -----
 cdist/conf/type/__directory/explorer/type     |  16 +++
 cdist/conf/type/__directory/gencode-remote    | 116 +++++++++++-------
 .../type/__directory/parameter/default/state  |   1 +
 8 files changed, 117 insertions(+), 189 deletions(-)
 delete mode 100755 cdist/conf/type/__directory/explorer/group
 delete mode 100755 cdist/conf/type/__directory/explorer/mode
 delete mode 100755 cdist/conf/type/__directory/explorer/owner
 create mode 100755 cdist/conf/type/__directory/explorer/stat
 delete mode 100755 cdist/conf/type/__directory/explorer/state
 create mode 100755 cdist/conf/type/__directory/explorer/type
 create mode 100644 cdist/conf/type/__directory/parameter/default/state

diff --git a/cdist/conf/type/__directory/explorer/group b/cdist/conf/type/__directory/explorer/group
deleted file mode 100755
index e5be37da..00000000
--- a/cdist/conf/type/__directory/explorer/group
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/bin/sh
-#
-# 2011 Nico Schottelius (nico-cdist at schottelius.org)
-#
-# This file is part of cdist.
-#
-# cdist is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# cdist is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with cdist. If not, see <http://www.gnu.org/licenses/>.
-#
-#
-# Check whether file exists or not
-#
-
-destination="/$__object_id"
-os=$("$__explorer/os")
-
-case "$os" in
-   "freebsd")
-      cmd="stat -f %Sg"
-      ;;
-   *)
-      cmd="stat -c %G"
-      ;;
-esac
-
-if [ -e "$destination" ]; then
-  $cmd "$destination"
-fi
-
diff --git a/cdist/conf/type/__directory/explorer/mode b/cdist/conf/type/__directory/explorer/mode
deleted file mode 100755
index f75b282b..00000000
--- a/cdist/conf/type/__directory/explorer/mode
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/bin/sh
-#
-# 2011 Nico Schottelius (nico-cdist at schottelius.org)
-#
-# This file is part of cdist.
-#
-# cdist is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# cdist is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with cdist. If not, see <http://www.gnu.org/licenses/>.
-#
-#
-# Check whether file exists or not
-#
-
-destination="/$__object_id"
-os=$("$__explorer/os")
-
-case "$os" in
-   "freebsd")
-      cmd="stat -f %Op"
-      ;;
-   *)
-      cmd="stat -c %a"
-      ;;
-esac
-
-if [ -e "$destination" ]; then
-  $cmd "$destination"
-fi
-
diff --git a/cdist/conf/type/__directory/explorer/owner b/cdist/conf/type/__directory/explorer/owner
deleted file mode 100755
index cebd199b..00000000
--- a/cdist/conf/type/__directory/explorer/owner
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/bin/sh
-#
-# 2011 Nico Schottelius (nico-cdist at schottelius.org)
-#
-# This file is part of cdist.
-#
-# cdist is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# cdist is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with cdist. If not, see <http://www.gnu.org/licenses/>.
-#
-#
-# Check whether file exists or not
-#
-
-destination="/$__object_id"
-os=$("$__explorer/os")
-
-case "$os" in
-   "freebsd")
-      cmd="stat -f %Su"
-      ;;  
-   *)  
-      cmd="stat -c %U"
-      ;;  
-esac
-
-if [ -e "$destination" ]; then
-  $cmd "$destination"
-fi
-
diff --git a/cdist/conf/type/__directory/explorer/stat b/cdist/conf/type/__directory/explorer/stat
new file mode 100755
index 00000000..2bd5d1c9
--- /dev/null
+++ b/cdist/conf/type/__directory/explorer/stat
@@ -0,0 +1,26 @@
+#!/bin/sh
+# 2013 Steven Armstrong (steven-cdist armstrong.cc)
+
+destination="/$__object_id"
+
+# nothing to work with, nothing we could do
+[ -e "$destination" ] || exit 0
+
+os=$("$__explorer/os")
+case "$os" in
+   "freebsd")
+      # FIXME: should be something like this based on man page, but can not test
+      stat -f "type: %ST
+owner: %Du %Su
+group: %Dg %Sg
+mode: %Op %Sp
+" "$destination"
+   ;;
+   *)
+      stat --printf="type: %F
+owner: %u %U
+group: %g %G
+mode: %a %A
+" "$destination"
+   ;;
+esac
diff --git a/cdist/conf/type/__directory/explorer/state b/cdist/conf/type/__directory/explorer/state
deleted file mode 100755
index 9bdd9024..00000000
--- a/cdist/conf/type/__directory/explorer/state
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/bin/sh
-#
-# 2011 Nico Schottelius (nico-cdist at schottelius.org)
-#
-# This file is part of cdist.
-#
-# cdist is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# cdist is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with cdist. If not, see <http://www.gnu.org/licenses/>.
-#
-#
-# Check whether file exists or not
-#
-
-destination="/$__object_id"
-
-if [ -e "$destination" ]; then
-   echo present
-else
-   echo absent
-fi
diff --git a/cdist/conf/type/__directory/explorer/type b/cdist/conf/type/__directory/explorer/type
new file mode 100755
index 00000000..6e6a2956
--- /dev/null
+++ b/cdist/conf/type/__directory/explorer/type
@@ -0,0 +1,16 @@
+#!/bin/sh
+# 2013 Steven Armstrong (steven-cdist armstrong.cc)
+
+destination="/$__object_id"
+
+if [ ! -e "$destination" ]; then
+   echo none
+elif [ -h "$destination" ]; then
+   echo symlink
+elif [ -f "$destination" ]; then
+   echo file
+elif [ -d "$destination" ]; then
+   echo directory
+else
+   echo unknown
+fi
diff --git a/cdist/conf/type/__directory/gencode-remote b/cdist/conf/type/__directory/gencode-remote
index f46a5967..ebe07318 100755
--- a/cdist/conf/type/__directory/gencode-remote
+++ b/cdist/conf/type/__directory/gencode-remote
@@ -1,6 +1,7 @@
 #!/bin/sh
 #
 # 2011-2012 Nico Schottelius (nico-cdist at schottelius.org)
+# 2013 Steven Armstrong (steven-cdist armstrong.cc)
 #
 # This file is part of cdist.
 #
@@ -19,53 +20,84 @@
 #
 
 destination="/$__object_id"
+state_should="$(cat "$__object/parameter/state")"
+type="$(cat "$__object/explorer/type")"
+stat_file="$__object/explorer/stat"
 
-state_is="$(cat "$__object/explorer/state")"
-owner_is="$(cat "$__object/explorer/owner")"
-group_is="$(cat "$__object/explorer/group")"
-mode_is="$(cat "$__object/explorer/mode")"
+# variable to keep track if we have to set directory attributes
+set_attributes=
 
-state_should="present"
-[ -f "$__object/parameter/state" ]     && state_should="$(cat "$__object/parameter/state")"
-mode=""
-[ -f "$__object/parameter/mode" ]      && mode="$(cat "$__object/parameter/mode")"
-owner=""
-[ -f "$__object/parameter/owner" ]     && owner="$(cat "$__object/parameter/owner")"
-group=""
-[ -f "$__object/parameter/group" ]     && group="$(cat "$__object/parameter/group")"
 mkdiropt=""
-[ -f "$__object/parameter/parents" ]   && mkdiropt="-p"
+[ -f "$__object/parameter/parents" ] && mkdiropt="-p"
+
 recursive=""
-[ -f "$__object/parameter/recursive" ] && recursive="-R"
+if [ -f "$__object/parameter/recursive" ]; then
+   recursive="-R"
+   # need to allways set attributes when recursive is given
+   # as we don't want to check all subfolders/files
+   set_attributes=1
+fi
+
+get_current_value() {
+   if [ -s "$stat_file" ]; then
+      _name="$1"
+      _value="$2"
+      case "$_value" in
+         [0-9]*)
+            _index=2
+         ;;
+         *)
+            _index=3
+         ;;
+      esac
+      awk '/'"$_name"':/ { print $'$_index' }' "$stat_file"
+      unset _name _value _index
+   fi
+}
+
+set_group() {
+   echo chgrp $recursive \"$1\" \"$destination\"
+}
+
+set_owner() {
+   echo chown $recursive \"$1\" \"$destination\"
+}
+
+set_mode() {
+   echo chmod $recursive \"$1\" \"$destination\"
+}
 
 case "$state_should" in
-    present)
-        if [ "$state_is" != "present" ]; then
-            echo mkdir $mkdiropt \"$destination\"
-        fi
+   present)
+      if [ "$type" != "directory" ];
+         # our destination is not a directory, remove whatever is there
+         # and then create our directory and set all attributes
+         set_attributes=1
+         cat << DONE
+rm -f "$destination"
+mkdir "$mkdiropt" "$destination"
+DONE
+      fi
 
-        # Mode settings
-        if [ "$mode" ] && [ "$mode_is" != "$mode" -o -n "$recursive" ]; then
-            echo chmod $recursive \"$mode\" \"$destination\"
-        fi
-
-        # Group
-        if [ "$group" ] && [ "$group_is" != "$group" -o -n "$recursive" ]; then
-            echo chgrp $recursive \"$group\" \"$destination\"
-        fi
-
-        # Owner
-        if [ "$owner" ] && [ "$owner_is" != "$owner" -o -n "$recursive" ]; then
-            echo chown $recursive \"$owner\" \"$destination\"
-        fi
-    ;;
-    absent)
-        if [ "$state_is" != "absent" ]; then
-          echo rm -rf \"$destination\"
-        fi
-    ;;
-    *)
-        echo "Unknown state: $state_should" >&2
-        exit 1
-    ;;
+      # Note: Mode - needs to happen last as a chown/chgrp can alter mode by
+      # clearing S_ISUID and S_ISGID bits (see chown(2))
+      for attribute in group owner mode; do
+         if [ -f "$__object/parameter/$attribute" ]; then
+            value_should="$(cat "$__object/parameter/$attribute")"
+            value_is="$(get_current_value "$attribute" "$value_should")"
+            if [ "$set_attributes" -o "$value_should" != "$value_is" ]; then
+               "set_$attribute" "$value_should"
+            fi
+         fi
+      done
+   ;;
+   absent)
+      if [ "$type" = "directory" ]; then
+         echo rm -rf \"$destination\"
+      fi
+   ;;
+   *)
+      echo "Unknown state: $state_should" >&2
+      exit 1
+   ;;
 esac
diff --git a/cdist/conf/type/__directory/parameter/default/state b/cdist/conf/type/__directory/parameter/default/state
new file mode 100644
index 00000000..e7f6134f
--- /dev/null
+++ b/cdist/conf/type/__directory/parameter/default/state
@@ -0,0 +1 @@
+present

From f5a39e52810cdefbdcd4b3cdc65aad2700555822 Mon Sep 17 00:00:00 2001
From: Steven Armstrong <steven@icarus.ethz.ch>
Date: Wed, 27 Nov 2013 16:06:34 +0100
Subject: [PATCH 16/29] add gpl header

Signed-off-by: Steven Armstrong <steven@icarus.ethz.ch>
---
 cdist/conf/type/__directory/explorer/stat | 17 +++++++++++++++++
 cdist/conf/type/__directory/explorer/type | 17 +++++++++++++++++
 2 files changed, 34 insertions(+)

diff --git a/cdist/conf/type/__directory/explorer/stat b/cdist/conf/type/__directory/explorer/stat
index 2bd5d1c9..d8cdbb9e 100755
--- a/cdist/conf/type/__directory/explorer/stat
+++ b/cdist/conf/type/__directory/explorer/stat
@@ -1,5 +1,22 @@
 #!/bin/sh
+#
 # 2013 Steven Armstrong (steven-cdist armstrong.cc)
+#
+# This file is part of cdist.
+#
+# cdist is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# cdist is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with cdist. If not, see <http://www.gnu.org/licenses/>.
+#
 
 destination="/$__object_id"
 
diff --git a/cdist/conf/type/__directory/explorer/type b/cdist/conf/type/__directory/explorer/type
index 6e6a2956..e723047c 100755
--- a/cdist/conf/type/__directory/explorer/type
+++ b/cdist/conf/type/__directory/explorer/type
@@ -1,5 +1,22 @@
 #!/bin/sh
+#
 # 2013 Steven Armstrong (steven-cdist armstrong.cc)
+#
+# This file is part of cdist.
+#
+# cdist is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# cdist is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with cdist. If not, see <http://www.gnu.org/licenses/>.
+#
 
 destination="/$__object_id"
 

From 6d5686229fd6da683ef692301ab356251992acff Mon Sep 17 00:00:00 2001
From: Steven Armstrong <steven@icarus.ethz.ch>
Date: Wed, 18 Sep 2013 10:40:29 +0200
Subject: [PATCH 17/29] only delete links; delete existing destination before
 creating links

Signed-off-by: Steven Armstrong <steven@icarus.ethz.ch>
---
 cdist/conf/type/__link/explorer/type          | 26 ++++++++++++++++
 cdist/conf/type/__link/gencode-remote         | 30 ++++++++++++++++---
 .../conf/type/__link/parameter/default/state  |  1 +
 3 files changed, 53 insertions(+), 4 deletions(-)
 create mode 100755 cdist/conf/type/__link/explorer/type
 create mode 100644 cdist/conf/type/__link/parameter/default/state

diff --git a/cdist/conf/type/__link/explorer/type b/cdist/conf/type/__link/explorer/type
new file mode 100755
index 00000000..c02b3af8
--- /dev/null
+++ b/cdist/conf/type/__link/explorer/type
@@ -0,0 +1,26 @@
+#!/bin/sh
+# 2013 Steven Armstrong (steven-cdist armstrong.cc)
+
+destination="/$__object_id"
+
+if [ ! -e "$destination" ]; then
+   echo none
+elif [ -h "$destination" ]; then
+   echo symlink
+elif [ -f "$destination" ]; then
+   type="$(cat "$__object/parameter/type")"
+   case "$type" in
+      hard)
+         link_count=$(ls -l "$destination" | awk '{ print $2 }')
+         if [ $link_count -gt 1 ]; then
+            echo hardlink
+            exit 0
+         fi
+      ;;
+   esac
+   echo file
+elif [ -d "$destination" ]; then
+   echo directory
+else
+   echo unknown
+fi
diff --git a/cdist/conf/type/__link/gencode-remote b/cdist/conf/type/__link/gencode-remote
index 2975ef69..2e41b7d9 100755
--- a/cdist/conf/type/__link/gencode-remote
+++ b/cdist/conf/type/__link/gencode-remote
@@ -1,6 +1,7 @@
 #!/bin/sh
 #
 # 2011-2012 Nico Schottelius (nico-cdist at schottelius.org)
+# 2013 Steven Armstrong (steven-cdist at armstrong.cc)
 #
 # This file is part of cdist.
 #
@@ -40,17 +41,38 @@ case "$type" in
 esac
 
 state_is="$(cat "$__object/explorer/state")"
-state_should=present
-[ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")"
+state_should="$(cat "$__object/parameter/state")"
 
 [ "$state_should" = "$state_is" ] && exit 0
 
+file_type="$(cat "$__object/explorer/type")"
 case "$state_should" in
     present)
-        echo ln ${lnopt} -f \"$source\" \"$destination\"
+        if [ "$file_type" = "directory" ]; then
+            # our destination is currently a directory, move it out of the way
+            cat << DONE
+destination_old="\$(mktemp "${destination}.cdist.XXXXXXXXXX")"
+mv "$destination" "\$destination_old"
+DONE
+        fi
+
+        # create our link
+        cat << DONE
+ln ${lnopt} -f "$source" "$destination"
+DONE
+
+        if [ "$file_type" = "directory" ]; then
+            # delete the legacy directory
+            cat << DONE
+rm -rf "\$destination_old"
+DONE
+        fi
     ;;
     absent)
-        echo rm -f \"$destination\"
+        # only delete if it is a sym/hard link
+        if [ "$file_type" = "symlink" -o "$file_type" = "hardlink" ]; then
+            echo rm -f \"$destination\"
+        fi
     ;;
     *)
         echo "Unknown state: $state_should" >&2
diff --git a/cdist/conf/type/__link/parameter/default/state b/cdist/conf/type/__link/parameter/default/state
new file mode 100644
index 00000000..e7f6134f
--- /dev/null
+++ b/cdist/conf/type/__link/parameter/default/state
@@ -0,0 +1 @@
+present

From 71b41df73324fa2f423b21c7d81b9baa4d6b131b Mon Sep 17 00:00:00 2001
From: Steven Armstrong <steven@icarus.ethz.ch>
Date: Tue, 15 Oct 2013 14:55:35 +0200
Subject: [PATCH 18/29] no late delete

Signed-off-by: Steven Armstrong <steven@icarus.ethz.ch>
---
 cdist/conf/type/__link/gencode-remote | 12 ++----------
 1 file changed, 2 insertions(+), 10 deletions(-)

diff --git a/cdist/conf/type/__link/gencode-remote b/cdist/conf/type/__link/gencode-remote
index 2e41b7d9..cbdfd30f 100755
--- a/cdist/conf/type/__link/gencode-remote
+++ b/cdist/conf/type/__link/gencode-remote
@@ -49,10 +49,9 @@ file_type="$(cat "$__object/explorer/type")"
 case "$state_should" in
     present)
         if [ "$file_type" = "directory" ]; then
-            # our destination is currently a directory, move it out of the way
+            # our destination is currently a directory, delete it
             cat << DONE
-destination_old="\$(mktemp "${destination}.cdist.XXXXXXXXXX")"
-mv "$destination" "\$destination_old"
+rm -rf "$destination"
 DONE
         fi
 
@@ -60,13 +59,6 @@ DONE
         cat << DONE
 ln ${lnopt} -f "$source" "$destination"
 DONE
-
-        if [ "$file_type" = "directory" ]; then
-            # delete the legacy directory
-            cat << DONE
-rm -rf "\$destination_old"
-DONE
-        fi
     ;;
     absent)
         # only delete if it is a sym/hard link

From abf291cb20106dcfb7c50587e2cb3408a296cf9a Mon Sep 17 00:00:00 2001
From: Steven Armstrong <steven@icarus.ethz.ch>
Date: Wed, 27 Nov 2013 16:08:12 +0100
Subject: [PATCH 19/29] add gpl header

Signed-off-by: Steven Armstrong <steven@icarus.ethz.ch>
---
 cdist/conf/type/__link/explorer/type | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/cdist/conf/type/__link/explorer/type b/cdist/conf/type/__link/explorer/type
index c02b3af8..579fd081 100755
--- a/cdist/conf/type/__link/explorer/type
+++ b/cdist/conf/type/__link/explorer/type
@@ -1,5 +1,25 @@
 #!/bin/sh
+#
 # 2013 Steven Armstrong (steven-cdist armstrong.cc)
+#
+# This file is part of cdist.
+#
+# cdist is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# cdist is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with cdist. If not, see <http://www.gnu.org/licenses/>.
+#
+#
+# Mostly a wrapper for ln
+#
 
 destination="/$__object_id"
 

From 61dc7291dce2e040b9d6ec026af506189b9d5694 Mon Sep 17 00:00:00 2001
From: Nico Schottelius <nico@bento.schottelius.org>
Date: Wed, 27 Nov 2013 16:28:06 +0100
Subject: [PATCH 20/29] ++changes(2.3.7)

Signed-off-by: Nico Schottelius <nico@bento.schottelius.org>
---
 docs/changelog | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/docs/changelog b/docs/changelog
index 7dfaefb2..3c185d48 100644
--- a/docs/changelog
+++ b/docs/changelog
@@ -6,6 +6,8 @@ Changelog
 
 2.3.7:
 	* Type __file: Secure the file transfer by using mktemp (Steven Armstrong)
+	* Type __link: Only remove links when state is absent (Steven Armstrong)
+	* Type __directory: Only remove directories when state is absent (Steven Armstrong)
 
 2.3.6: 2013-11-25
 	* New Type: __locale

From bc9d40df372c0c2f97c1be4d0634958815e3340f Mon Sep 17 00:00:00 2001
From: Nico Schottelius <nico@bento.schottelius.org>
Date: Thu, 28 Nov 2013 14:10:15 +0100
Subject: [PATCH 21/29] ignore lock files

Signed-off-by: Nico Schottelius <nico@bento.schottelius.org>
---
 .gitignore | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.gitignore b/.gitignore
index 76ed1fcb..63f8076a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -29,3 +29,4 @@ cdist/version.py
 build
 .lock-*
 .git-current-branch
+.lock*

From 8998ea929890e918eab76d84c6e2825a7a25d223 Mon Sep 17 00:00:00 2001
From: Nico Schottelius <nico@bento.schottelius.org>
Date: Fri, 29 Nov 2013 16:02:17 +0100
Subject: [PATCH 22/29] ++changes(2.3.7)

Signed-off-by: Nico Schottelius <nico@bento.schottelius.org>
---
 docs/changelog | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/docs/changelog b/docs/changelog
index 3c185d48..ec584026 100644
--- a/docs/changelog
+++ b/docs/changelog
@@ -6,8 +6,9 @@ Changelog
 
 2.3.7:
 	* Type __file: Secure the file transfer by using mktemp (Steven Armstrong)
-	* Type __link: Only remove links when state is absent (Steven Armstrong)
-	* Type __directory: Only remove directories when state is absent (Steven Armstrong)
+	* Type __file: Only remove file when state is absent (Steven Armstrong)
+	* Type __link: Only remove link when state is absent (Steven Armstrong)
+	* Type __directory: Only remove directory when state is absent (Steven Armstrong)
 
 2.3.6: 2013-11-25
 	* New Type: __locale

From 48923d23d88adb9052b17cec5e4ab49fbbc262cf Mon Sep 17 00:00:00 2001
From: Nico Schottelius <nico@bento.schottelius.org>
Date: Sun, 1 Dec 2013 18:37:08 +0100
Subject: [PATCH 23/29] if ... THEN ;-)

Signed-off-by: Nico Schottelius <nico@bento.schottelius.org>
---
 cdist/conf/type/__directory/gencode-remote | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/cdist/conf/type/__directory/gencode-remote b/cdist/conf/type/__directory/gencode-remote
index ebe07318..23fa4ed3 100755
--- a/cdist/conf/type/__directory/gencode-remote
+++ b/cdist/conf/type/__directory/gencode-remote
@@ -1,6 +1,6 @@
 #!/bin/sh
 #
-# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org)
+# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org)
 # 2013 Steven Armstrong (steven-cdist armstrong.cc)
 #
 # This file is part of cdist.
@@ -69,7 +69,7 @@ set_mode() {
 
 case "$state_should" in
    present)
-      if [ "$type" != "directory" ];
+      if [ "$type" != "directory" ]; then
          # our destination is not a directory, remove whatever is there
          # and then create our directory and set all attributes
          set_attributes=1

From 7cf0d60b085f29716597ce11748e290b12a7bbfc Mon Sep 17 00:00:00 2001
From: Nico Schottelius <nico@bento.schottelius.org>
Date: Sun, 1 Dec 2013 18:42:07 +0100
Subject: [PATCH 24/29] catch permissionserror when deleting old cache

Signed-off-by: Nico Schottelius <nico@bento.schottelius.org>
---
 cdist/exec/local.py | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/cdist/exec/local.py b/cdist/exec/local.py
index 3a3ac706..88b49be9 100644
--- a/cdist/exec/local.py
+++ b/cdist/exec/local.py
@@ -186,8 +186,13 @@ class Local(object):
     def save_cache(self):
         destination = os.path.join(self.cache_path, self.target_host)
         self.log.debug("Saving " + self.base_path + " to " + destination)
-        if os.path.exists(destination):
-            shutil.rmtree(destination)
+
+        try:
+            if os.path.exists(destination):
+                shutil.rmtree(destination)
+        except PermissionError as e:
+            raise cdist.Error("Cannot delete old cache %s: %s" % (destination, e))
+
         shutil.move(self.base_path, destination)
 
     def _create_conf_path_and_link_conf_dirs(self):

From 538a5b4964db93afc070ea89b84ff3ce6109d1fa Mon Sep 17 00:00:00 2001
From: Nico Schottelius <nico@bento.schottelius.org>
Date: Sun, 1 Dec 2013 18:42:43 +0100
Subject: [PATCH 25/29] ++changes

Signed-off-by: Nico Schottelius <nico@bento.schottelius.org>
---
 docs/changelog | 1 +
 1 file changed, 1 insertion(+)

diff --git a/docs/changelog b/docs/changelog
index ec584026..67eaca1a 100644
--- a/docs/changelog
+++ b/docs/changelog
@@ -9,6 +9,7 @@ Changelog
 	* Type __file: Only remove file when state is absent (Steven Armstrong)
 	* Type __link: Only remove link when state is absent (Steven Armstrong)
 	* Type __directory: Only remove directory when state is absent (Steven Armstrong)
+	* Core: Fix backtrace when cache cannot be deleted
 
 2.3.6: 2013-11-25
 	* New Type: __locale

From d074713b94f026e4de78bb3c07b777a3066e7d85 Mon Sep 17 00:00:00 2001
From: Daniel Heule <daniel.heule@gmail.com>
Date: Mon, 2 Dec 2013 13:27:42 +0100
Subject: [PATCH 26/29] Fix explorer and globalopts issue in type
 __package_zypper

Fixes #215.

Signed-off-by: Nico Schottelius <nico@bento.schottelius.org>
---
 cdist/conf/type/__package_zypper/explorer/pkg_version |  2 +-
 cdist/conf/type/__package_zypper/gencode-remote       | 11 +++++++++--
 2 files changed, 10 insertions(+), 3 deletions(-)
 mode change 100755 => 100644 cdist/conf/type/__package_zypper/explorer/pkg_version
 mode change 100755 => 100644 cdist/conf/type/__package_zypper/gencode-remote

diff --git a/cdist/conf/type/__package_zypper/explorer/pkg_version b/cdist/conf/type/__package_zypper/explorer/pkg_version
old mode 100755
new mode 100644
index fb3b7753..655b464d
--- a/cdist/conf/type/__package_zypper/explorer/pkg_version
+++ b/cdist/conf/type/__package_zypper/explorer/pkg_version
@@ -27,4 +27,4 @@ else
    name="$__object_id"
 fi
 
-rpm -q --whatprovides "$name" 2>/dev/null || true
+rpm -q --whatprovides "$name"  | grep -v 'no package provides' || true
diff --git a/cdist/conf/type/__package_zypper/gencode-remote b/cdist/conf/type/__package_zypper/gencode-remote
old mode 100755
new mode 100644
index ca9aec33..d1766126
--- a/cdist/conf/type/__package_zypper/gencode-remote
+++ b/cdist/conf/type/__package_zypper/gencode-remote
@@ -39,15 +39,22 @@ else
    state_should="present"
 fi
 
+pkg_version="$(cat "$__object/explorer/pkg_version")"
+if [ -z "$pkg_version" ]; then
+    state_is="absent"
+else
+    state_is="present"
+fi
+
 # Exit if nothing is needed to be done
 [ "$state_is" = "$state_should" ] && exit 0
 
 case "$state_should" in
    present)
-         echo zypper "$globalopts" install --auto-agree-with-licenses \"$name\"
+         echo zypper $globalopts install --auto-agree-with-licenses \"$name\" ">/dev/null"
    ;;
    absent)
-         echo pacman "$globalopts" remove \"$name\"
+         echo zypper $globalopts remove \"$name\" ">/dev/null"
    ;;
    *)
       echo "Unknown state: $state_should" >&2

From 1b36ed88f0b8d6b10ff7ae9478b83d0603bd0398 Mon Sep 17 00:00:00 2001
From: Nico Schottelius <nico@bento.schottelius.org>
Date: Mon, 2 Dec 2013 13:29:17 +0100
Subject: [PATCH 27/29] ++changes(2.3.7)

Signed-off-by: Nico Schottelius <nico@bento.schottelius.org>
---
 docs/changelog | 1 +
 1 file changed, 1 insertion(+)

diff --git a/docs/changelog b/docs/changelog
index 67eaca1a..25079179 100644
--- a/docs/changelog
+++ b/docs/changelog
@@ -9,6 +9,7 @@ Changelog
 	* Type __file: Only remove file when state is absent (Steven Armstrong)
 	* Type __link: Only remove link when state is absent (Steven Armstrong)
 	* Type __directory: Only remove directory when state is absent (Steven Armstrong)
+	* Type __package_zypper: Fix explorer and parameter issue (Daniel Heule)
 	* Core: Fix backtrace when cache cannot be deleted
 
 2.3.6: 2013-11-25

From 9d86f8c9b7f379c90522ce99d5abde3c43474531 Mon Sep 17 00:00:00 2001
From: Nico Schottelius <nico@bento.schottelius.org>
Date: Mon, 2 Dec 2013 15:16:31 +0100
Subject: [PATCH 28/29] 2.3.7 release

Signed-off-by: Nico Schottelius <nico@bento.schottelius.org>
---
 docs/changelog | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/changelog b/docs/changelog
index 25079179..b6122bec 100644
--- a/docs/changelog
+++ b/docs/changelog
@@ -4,7 +4,7 @@ Changelog
 	* Changes are always commented with their author in (braces)
 	* Exception: No braces means author == Nico Schottelius
 
-2.3.7:
+2.3.7: 2013-12-02
 	* Type __file: Secure the file transfer by using mktemp (Steven Armstrong)
 	* Type __file: Only remove file when state is absent (Steven Armstrong)
 	* Type __link: Only remove link when state is absent (Steven Armstrong)

From a95167b374e4de8dd16423017a477e6336f2d05d Mon Sep 17 00:00:00 2001
From: Nico Schottelius <nico@bento.schottelius.org>
Date: Mon, 2 Dec 2013 15:49:02 +0100
Subject: [PATCH 29/29] remove quotes from mkdiropt

Signed-off-by: Nico Schottelius <nico@bento.schottelius.org>
---
 cdist/conf/type/__directory/gencode-remote | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/cdist/conf/type/__directory/gencode-remote b/cdist/conf/type/__directory/gencode-remote
index 23fa4ed3..800fc6e4 100755
--- a/cdist/conf/type/__directory/gencode-remote
+++ b/cdist/conf/type/__directory/gencode-remote
@@ -75,7 +75,7 @@ case "$state_should" in
          set_attributes=1
          cat << DONE
 rm -f "$destination"
-mkdir "$mkdiropt" "$destination"
+mkdir $mkdiropt "$destination"
 DONE
       fi