[Libguestfs] [PATCH 3/3] fish: edit: Preserve permissions, UID, GID, SELinux context when editing files (RHBZ#788641).
Richard W.M. Jones
rjones at redhat.com
Fri Feb 10 10:39:47 UTC 2012
--
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
libguestfs lets you edit virtual machines. Supports shell scripting,
bindings from many languages. http://libguestfs.org
-------------- next part --------------
>From 0c24a2dd904a2a33f75c6580e671633f1ee80b90 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones at redhat.com>
Date: Fri, 10 Feb 2012 10:32:55 +0000
Subject: [PATCH 3/3] fish: edit: Preserve permissions, UID, GID, SELinux
context when editing files (RHBZ#788641).
---
fish/edit.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++
fish/test-edit.sh | 11 ++++++-
2 files changed, 92 insertions(+), 1 deletions(-)
diff --git a/fish/edit.c b/fish/edit.c
index 908a3a3..517c098 100644
--- a/fish/edit.c
+++ b/fish/edit.c
@@ -31,6 +31,8 @@
#include "fish.h"
static char *generate_random_name (const char *filename);
+static int copy_attributes (const char *src, const char *dest);
+static int feature_available (guestfs_h *g, const char *feature);
/* guestfish edit command, suggested by J?n Ondrej, implemented by RWMJ */
@@ -127,6 +129,12 @@ run_edit (const char *cmd, size_t argc, char *argv[])
if (guestfs_upload (g, filename, newname) == -1)
goto error3;
+ /* Set the permissions, UID, GID and SELinux context of the new
+ * file to match the old file (RHBZ#788641).
+ */
+ if (copy_attributes (remotefilename, newname) == -1)
+ goto error3;
+
if (guestfs_mv (g, newname, remotefilename) == -1)
goto error3;
@@ -178,3 +186,77 @@ generate_random_name (const char *filename)
return ret; /* caller will free */
}
+
+static int
+copy_attributes (const char *src, const char *dest)
+{
+ struct guestfs_stat *stat;
+ int has_linuxxattrs;
+ char *selinux_context = NULL;
+ size_t selinux_context_size;
+
+ has_linuxxattrs = feature_available (g, "linuxxattrs");
+
+ /* Get the mode. */
+ stat = guestfs_stat (g, src);
+ if (stat == NULL)
+ return -1;
+
+ /* Get the SELinux context. XXX Should we copy over other extended
+ * attributes too?
+ */
+ if (has_linuxxattrs) {
+ guestfs_error_handler_cb old_error_cb;
+ void *old_error_data;
+ old_error_cb = guestfs_get_error_handler (g, &old_error_data);
+ guestfs_set_error_handler (g, NULL, NULL);
+
+ selinux_context = guestfs_getxattr (g, src, "security.selinux",
+ &selinux_context_size);
+ /* selinux_context could be NULL. This isn't an error. */
+
+ guestfs_set_error_handler (g, old_error_cb, old_error_data);
+ }
+
+ /* Set the permissions (inc. sticky and set*id bits), UID, GID. */
+ if (guestfs_chmod (g, stat->mode & 07777, dest) == -1) {
+ guestfs_free_stat (stat);
+ return -1;
+ }
+ if (guestfs_chown (g, stat->uid, stat->gid, dest) == -1) {
+ guestfs_free_stat (stat);
+ return -1;
+ }
+ guestfs_free_stat (stat);
+
+ /* Set the SELinux context. */
+ if (has_linuxxattrs && selinux_context) {
+ if (guestfs_setxattr (g, "security.selinux", selinux_context,
+ (int) selinux_context_size, dest) == -1) {
+ free (selinux_context);
+ return -1;
+ }
+ }
+ free (selinux_context);
+
+ return 0;
+}
+
+static int
+feature_available (guestfs_h *g, const char *feature)
+{
+ /* If there's an error we should ignore it, so to do that we have to
+ * temporarily replace the error handler with a null one.
+ */
+ guestfs_error_handler_cb old_error_cb;
+ void *old_error_data;
+ old_error_cb = guestfs_get_error_handler (g, &old_error_data);
+ guestfs_set_error_handler (g, NULL, NULL);
+
+ const char *groups[] = { feature, NULL };
+ int r = guestfs_available (g, (char * const *) groups);
+
+ guestfs_set_error_handler (g, old_error_cb, old_error_data);
+
+ return r == 0 ? 1 : 0;
+}
diff --git a/fish/test-edit.sh b/fish/test-edit.sh
index ff38d1c..93b2e90 100755
--- a/fish/test-edit.sh
+++ b/fish/test-edit.sh
@@ -36,13 +36,22 @@ export EDITOR="echo second line of text >>"
output=$(
../fish/guestfish -N fs -m /dev/sda1 <<EOF
write /file.txt "this is a test\n"
+chmod 0600 /file.txt
+chown 10 11 /file.txt
edit /file.txt
cat /file.txt
+stat /file.txt | grep mode:
+stat /file.txt | grep uid:
+stat /file.txt | grep gid:
EOF
)
if [ "$output" != "this is a test
-second line of text" ]; then
+second line of text
+
+mode: 33152
+uid: 10
+gid: 11" ]; then
echo "$0: error: output of guestfish after edit command did not match expected output"
echo "$output"
exit 1
--
1.7.9
More information about the Libguestfs
mailing list