mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-21 22:53:37 +00:00
fish: edit: Preserve permissions, UID, GID, SELinux context when editing files (RHBZ#788641).
This commit is contained in:
82
fish/edit.c
82
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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user