summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard W.M. Jones <rjones@redhat.com>2012-07-18 12:33:16 +0100
committerRichard W.M. Jones <rjones@redhat.com>2012-08-05 21:26:44 +0100
commitaf0051927ebf30f76e20741999c0ce19b988f35e (patch)
tree11b948e2fbc3fd670ce9f04ba204b22b07e2b48d
parentad6901ad4aaf9683179e26391fe318cb9e8f270b (diff)
downloadlibguestfs-af0051927ebf30f76e20741999c0ce19b988f35e.tar.gz
libguestfs-af0051927ebf30f76e20741999c0ce19b988f35e.tar.xz
libguestfs-af0051927ebf30f76e20741999c0ce19b988f35e.zip
tar-in: Add --no-same-owner flag to tar command when target filesystem doesn't support chown (RHBZ#840572).
When using tar-in or tools built around it such as virt-make-fs, if the target filesystem is vfat then unpacking the tarball would fail because tar tries to chown(2) files and fails. You would see errors such as: tar: <file>: Cannot change ownership to uid 500, gid 500: Operation not permitted This change detects whether the target filesystem supports chown(2). If not, it adds the --no-same-owner flag to tar to stop it from trying to change the ownership of newly created files. (cherry picked from commit 50780a84f65ec5d76605691cea889392c2730f54)
-rw-r--r--daemon/tar.c57
1 files changed, 54 insertions, 3 deletions
diff --git a/daemon/tar.c b/daemon/tar.c
index 9295f0d7..83e68dd3 100644
--- a/daemon/tar.c
+++ b/daemon/tar.c
@@ -36,6 +36,51 @@ optgroup_xz_available (void)
return prog_exists ("xz");
}
+/* Detect if chown(2) is supported on the target directory. */
+static int
+is_chown_supported (const char *dir)
+{
+ size_t len = sysroot_len + strlen (dir) + 64;
+ char buf[len];
+ int fd, r, saved_errno;
+
+ /* Create a randomly named file. */
+ snprintf (buf, len, "%s%s/XXXXXXXX.XXX", sysroot, dir);
+ if (random_name (buf) == -1) {
+ reply_with_perror ("random_name");
+ return -1;
+ }
+
+ /* Maybe 'dir' is not a directory or filesystem not writable? */
+ fd = open (buf, O_WRONLY|O_CREAT|O_NOCTTY|O_CLOEXEC, 0666);
+ if (fd == -1) {
+ reply_with_perror ("%s", dir);
+ return -1;
+ }
+
+ /* This is the test. */
+ r = fchown (fd, 1000, 1000);
+ saved_errno = errno;
+
+ /* Make sure the test file is removed. */
+ close (fd);
+ unlink (buf);
+
+ if (r == -1 && saved_errno == EPERM) {
+ /* This means chown is not supported by the filesystem. */
+ return 0;
+ }
+
+ if (r == -1) {
+ /* Some other error? */
+ reply_with_perror_errno (saved_errno, "unexpected error in fchown");
+ return -1;
+ }
+
+ /* Else chown is supported. */
+ return 1;
+}
+
/* Read the error file. Returns a string that the caller must free. */
static char *
read_error_file (char *error_file)
@@ -75,7 +120,11 @@ do_tXz_in (const char *dir, const char *filter)
FILE *fp;
char *cmd;
char error_file[] = "/tmp/tarXXXXXX";
- int fd;
+ int fd, chown_supported;
+
+ chown_supported = is_chown_supported (dir);
+ if (chown_supported == -1)
+ return -1;
fd = mkstemp (error_file);
if (fd == -1) {
@@ -86,8 +135,10 @@ do_tXz_in (const char *dir, const char *filter)
close (fd);
/* "tar -C /sysroot%s -xf -" but we have to quote the dir. */
- if (asprintf_nowarn (&cmd, "tar -C %R -%sxf - 2> %s",
- dir, filter, error_file) == -1) {
+ if (asprintf_nowarn (&cmd, "tar -C %R -%sxf - %s2> %s",
+ dir, filter,
+ chown_supported ? "" : "--no-same-owner ",
+ error_file) == -1) {
err = errno;
r = cancel_receive ();
errno = err;