edit: Preserve file permissions, UID, GID, SELinux context on edited files. (RHBZ#788641)

This commit is contained in:
Richard W.M. Jones
2012-02-08 18:05:29 +00:00
parent 016ae77e6c
commit 24d7889eba
3 changed files with 93 additions and 0 deletions

View File

@@ -38,5 +38,14 @@ newline" ]; then
fi
fi
# Verify the mode of /etc/test3 is still 0600 and the UID:GID is 10:11.
# See tests/guests/guest-aux/make-fedora-img.pl and RHBZ#788641.
if [ "$(../fish/guestfish -i -a test.img --ro lstat /etc/test3 | grep -E '^(mode|uid|gid):' | sort)" != "gid: 11
mode: 33152
uid: 10" ]; then
echo "$0: error: editing /etc/test3 did not preserve permissions or ownership"
exit 1
fi
# Discard test image.
rm test.img

View File

@@ -55,6 +55,8 @@ static const char *perl_expr = NULL;
static void edit (const char *filename, const char *root);
static char *edit_interactively (const char *tmpfile);
static char *edit_non_interactively (const char *tmpfile);
static int copy_attributes (const char *src, const char *dest);
static int feature_available (guestfs_h *g, const char *feature);
static int is_windows (guestfs_h *g, const char *root);
static char *windows_path (guestfs_h *g, const char *root, const char *filename);
static char *generate_random_name (const char *filename);
@@ -357,6 +359,12 @@ edit (const char *filename, const char *root)
if (guestfs_upload (g, upload_from, newname) == -1)
goto error;
/* Set the permissions, UID, GID and SELinux context of the new
* file to match the old file (RHBZ#788641).
*/
if (copy_attributes (filename, newname) == -1)
goto error;
/* Backup or overwrite the file. */
if (backup_extension) {
backupname = generate_backup_name (filename);
@@ -510,6 +518,80 @@ edit_non_interactively (const char *tmpfile)
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;
}
static int
is_windows (guestfs_h *g, const char *root)
{

View File

@@ -173,6 +173,8 @@ d
e
f
');
$g->chown(10, 11, '/etc/test3');
$g->chmod(0600, '/etc/test3');
$g->write('/bin/test1', 'abcdefg');
$g->write('/bin/test2', 'zxcvbnm');
$g->write('/bin/test3', '1234567');