]> wimlib.net Git - wimlib/blobdiff - src/unix_apply.c
mount_image.c: add fallback definitions of RENAME_* constants
[wimlib] / src / unix_apply.c
index 3b31e194287fedf85326c7d42a95c857241a7f33..89b6f5f6a8465ca51ab1c76963edee457e351592 100644 (file)
@@ -3,7 +3,7 @@
  */
 
 /*
- * Copyright (C) 2012-2016 Eric Biggers
+ * Copyright (C) 2012-2018 Eric Biggers
  *
  * This file is free software; you can redistribute it and/or modify it under
  * the terms of the GNU Lesser General Public License as published by the Free
@@ -16,7 +16,7 @@
  * details.
  *
  * You should have received a copy of the GNU Lesser General Public License
- * along with this file; if not, see http://www.gnu.org/licenses/.
+ * along with this file; if not, see https://www.gnu.org/licenses/.
  */
 
 #ifdef HAVE_CONFIG_H
@@ -64,8 +64,8 @@ unix_get_supported_features(const char *target,
        supported_features->unix_data = 1;
        supported_features->timestamps = 1;
        supported_features->case_sensitive_filenames = 1;
-#ifdef HAVE_XATTR_SUPPORT
-       supported_features->linux_xattrs = 1;
+#ifdef HAVE_LINUX_XATTR_SUPPORT
+       supported_features->xattrs = 1;
 #endif
        return 0;
 }
@@ -268,38 +268,58 @@ unix_set_mode(int fd, const char *path, mode_t mode)
        return WIMLIB_ERR_SET_SECURITY;
 }
 
-#ifdef HAVE_XATTR_SUPPORT
+#ifdef HAVE_LINUX_XATTR_SUPPORT
 /* Apply extended attributes to a file */
 static int
 apply_linux_xattrs(int fd, const struct wim_inode *inode,
                   const char *path, struct unix_apply_ctx *ctx,
-                  const void *entries, size_t entries_size)
+                  const void *entries, size_t entries_size, bool is_old_format)
 {
        const void * const entries_end = entries + entries_size;
-       char name[XATTR_NAME_MAX + 1];
+       char name[WIM_XATTR_NAME_MAX + 1];
 
-       for (const struct wimlib_xattr_entry *entry = entries;
-            (void *)entry < entries_end; entry = xattr_entry_next(entry))
+       for (const void *entry = entries;
+            entry < entries_end;
+            entry = is_old_format ? (const void *)old_xattr_entry_next(entry) :
+                                    (const void *)xattr_entry_next(entry))
        {
+               bool valid;
                u16 name_len;
                const void *value;
                u32 value_len;
                int res;
 
-               if (!valid_xattr_entry(entry, entries_end - (void *)entry)) {
+               if (is_old_format) {
+                       valid = old_valid_xattr_entry(entry,
+                                                     entries_end - entry);
+               } else {
+                       valid = valid_xattr_entry(entry, entries_end - entry);
+               }
+               if (!valid) {
                        if (!path) {
                                path = unix_build_inode_extraction_path(inode,
                                                                        ctx);
                        }
-                       ERROR("\"%s\": extended attribute is corrupt", path);
+                       ERROR("\"%s\": extended attribute is corrupt or unsupported",
+                             path);
                        return WIMLIB_ERR_INVALID_XATTR;
                }
-               name_len = le16_to_cpu(entry->name_len);
-               memcpy(name, entry->name, name_len);
-               name[name_len] = '\0';
+               if (is_old_format) {
+                       const struct wimlib_xattr_entry_old *e = entry;
 
-               value = entry->name + name_len;
-               value_len = le32_to_cpu(entry->value_len);
+                       name_len = le16_to_cpu(e->name_len);
+                       memcpy(name, e->name, name_len);
+                       value = e->name + name_len;
+                       value_len = le32_to_cpu(e->value_len);
+               } else {
+                       const struct wim_xattr_entry *e = entry;
+
+                       name_len = e->name_len;
+                       memcpy(name, e->name, name_len);
+                       value = e->name + name_len + 1;
+                       value_len = le16_to_cpu(e->value_len);
+               }
+               name[name_len] = '\0';
 
                if (fd >= 0)
                        res = fsetxattr(fd, name, value, value_len, 0);
@@ -311,7 +331,7 @@ apply_linux_xattrs(int fd, const struct wim_inode *inode,
                                path = unix_build_inode_extraction_path(inode,
                                                                        ctx);
                        }
-                       if (is_security_xattr(name) &&
+                       if (is_linux_security_xattr(name) &&
                            (ctx->common.extract_flags &
                             WIMLIB_EXTRACT_FLAG_STRICT_ACLS))
                        {
@@ -325,46 +345,79 @@ apply_linux_xattrs(int fd, const struct wim_inode *inode,
        }
        return 0;
 }
-#endif /* HAVE_XATTR_SUPPORT */
+#endif /* HAVE_LINUX_XATTR_SUPPORT */
 
-/* Apply standard UNIX permissions (uid, gid, and mode) to a file */
+/*
+ * Apply UNIX-specific metadata to a file if available.  This includes standard
+ * UNIX permissions (uid, gid, and mode) and possibly extended attributes too.
+ *
+ * Note that some xattrs which grant privileges, e.g. security.capability, are
+ * cleared by Linux on chown(), even when running as root.  Also, when running
+ * as non-root, if we need to chmod() the file to readonly, we can't do that
+ * before setting xattrs because setxattr() requires write permission.  These
+ * restrictions result in the following ordering which we follow: chown(),
+ * setxattr(), then chmod().
+ *
+ * N.B. the file may be specified by either 'fd' (for regular files) or 'path',
+ * and it may be a symlink.  For symlinks we need lchown() and lsetxattr() but
+ * need to skip the chmod(), since mode bits are not meaningful for symlinks.
+ */
 static int
-apply_unix_permissions(int fd, const struct wim_inode *inode,
-                      const char *path, struct unix_apply_ctx *ctx,
-                      const struct wimlib_unix_data *dat)
+apply_unix_metadata(int fd, const struct wim_inode *inode,
+                   const char *path, struct unix_apply_ctx *ctx)
 {
+       bool have_dat;
+       struct wimlib_unix_data dat;
+#ifdef HAVE_LINUX_XATTR_SUPPORT
+       const void *entries;
+       u32 entries_size;
+       bool is_old_format;
+#endif
        int ret;
 
-       ret = unix_set_owner_and_group(fd, path, dat->uid, dat->gid);
-       if (ret) {
-               if (!path)
-                       path = unix_build_inode_extraction_path(inode, ctx);
-               if (ctx->common.extract_flags &
-                   WIMLIB_EXTRACT_FLAG_STRICT_ACLS)
-               {
-                       ERROR_WITH_ERRNO("\"%s\": unable to set uid=%"PRIu32" and gid=%"PRIu32,
-                                        path, dat->uid, dat->gid);
-                       return ret;
+       have_dat = inode_get_unix_data(inode, &dat);
+
+       if (have_dat) {
+               ret = unix_set_owner_and_group(fd, path, dat.uid, dat.gid);
+               if (ret) {
+                       if (!path)
+                               path = unix_build_inode_extraction_path(inode, ctx);
+                       if (ctx->common.extract_flags &
+                           WIMLIB_EXTRACT_FLAG_STRICT_ACLS)
+                       {
+                               ERROR_WITH_ERRNO("\"%s\": unable to set uid=%"PRIu32" and gid=%"PRIu32,
+                                                path, dat.uid, dat.gid);
+                               return ret;
+                       }
+                       WARNING_WITH_ERRNO("\"%s\": unable to set uid=%"PRIu32" and gid=%"PRIu32,
+                                          path, dat.uid, dat.gid);
                }
-               WARNING_WITH_ERRNO("\"%s\": unable to set uid=%"PRIu32" and gid=%"PRIu32,
-                                  path, dat->uid, dat->gid);
        }
 
-       if (!inode_is_symlink(inode)) {
-               ret = unix_set_mode(fd, path, dat->mode);
+#ifdef HAVE_LINUX_XATTR_SUPPORT
+       entries = inode_get_linux_xattrs(inode, &entries_size, &is_old_format);
+       if (entries) {
+               ret = apply_linux_xattrs(fd, inode, path, ctx,
+                                        entries, entries_size, is_old_format);
+               if (ret)
+                       return ret;
+       }
+#endif
+
+       if (have_dat && !inode_is_symlink(inode)) {
+               ret = unix_set_mode(fd, path, dat.mode);
                if (ret) {
                        if (!path)
-                               path = unix_build_inode_extraction_path(inode,
-                                                                       ctx);
+                               path = unix_build_inode_extraction_path(inode, ctx);
                        if (ctx->common.extract_flags &
                            WIMLIB_EXTRACT_FLAG_STRICT_ACLS)
                        {
                                ERROR_WITH_ERRNO("\"%s\": unable to set mode=0%"PRIo32,
-                                                path, dat->mode);
+                                                path, dat.mode);
                                return ret;
                        }
                        WARNING_WITH_ERRNO("\"%s\": unable to set mode=0%"PRIo32,
-                                          path, dat->mode);
+                                          path, dat.mode);
                }
        }
 
@@ -389,25 +442,9 @@ unix_set_metadata(int fd, const struct wim_inode *inode,
                path = unix_build_inode_extraction_path(inode, ctx);
 
        if (ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_UNIX_DATA) {
-               struct wimlib_unix_data dat;
-       #ifdef HAVE_XATTR_SUPPORT
-               const void *entries;
-               u32 entries_size;
-
-               entries = inode_get_linux_xattrs(inode, &entries_size);
-               if (entries) {
-                       ret = apply_linux_xattrs(fd, inode, path, ctx,
-                                                entries, entries_size);
-                       if (ret)
-                               return ret;
-               }
-       #endif
-               if (inode_get_unix_data(inode, &dat)) {
-                       ret = apply_unix_permissions(fd, inode, path, ctx,
-                                                    &dat);
-                       if (ret)
-                               return ret;
-               }
+               ret = apply_unix_metadata(fd, inode, path, ctx);
+               if (ret)
+                       return ret;
        }
 
        ret = unix_set_timestamps(fd, path, inode->i_last_access_time,