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 .
-#
-#
-# 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 .
#
-#
-# __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 .
#
-#
-# __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