]> wimlib.net Git - wimlib/blobdiff - include/wimlib/xattr.h
Capture and apply extended attributes on Windows
[wimlib] / include / wimlib / xattr.h
index 2fc5f6dc79ba6b2d17aae19e8e8df88af2521086..2d297245aaf3a808115989d05d21d885fd876b3c 100644 (file)
@@ -7,24 +7,82 @@
 #include "wimlib/tagged_items.h"
 #include "wimlib/util.h"
 
-#undef HAVE_XATTR_SUPPORT
+#undef HAVE_LINUX_XATTR_SUPPORT
 #if defined(HAVE_SYS_XATTR_H) && \
        defined(HAVE_LLISTXATTR) && defined(HAVE_LGETXATTR) && \
        defined(HAVE_FSETXATTR) && defined(HAVE_LSETXATTR)
-#  define HAVE_XATTR_SUPPORT 1
+#  define HAVE_LINUX_XATTR_SUPPORT 1
 #endif
 
+#define WIM_XATTR_NAME_MAX 255
+#define WIM_XATTR_SIZE_MAX 65535
+
+/*
+ * On-disk format of each extended attribute (xattr, or EA) entry in a metadata
+ * item tagged with TAG_XATTRS.  This is the preferred xattr format, since it is
+ * also used by WIMGAPI and DISM starting in Windows 10 version 1607.
+ */
+struct wim_xattr_entry {
+
+       /* length of xattr value in bytes */
+       le16 value_len;
+
+       /* length of xattr name in bytes, excluding the null terminator */
+       u8 name_len;
+
+       /* flags: 0 or 0x80 (FILE_NEED_EA) */
+       u8 flags;
+
+       /* followed by the xattr name *with* a null terminator */
+       char name[0];
+
+       /* followed by the xattr value */
+       /* u8 value[0]; */
+
+       /* no padding at end! */
+} _packed_attribute;
+
+static inline size_t
+xattr_entry_size(const struct wim_xattr_entry *entry)
+{
+       STATIC_ASSERT(sizeof(*entry) == 4);
+
+       return sizeof(*entry) + entry->name_len + 1 +
+               le16_to_cpu(entry->value_len);
+}
+
+/* minimum is a 1-byte name (plus null terminator) and an empty value */
+#define XATTR_ENTRY_MIN_SIZE (sizeof(struct wim_xattr_entry) + 2)
+
+static inline struct wim_xattr_entry *
+xattr_entry_next(const struct wim_xattr_entry *entry)
+{
+       return (void *)entry + xattr_entry_size(entry);
+}
+
+static inline bool
+valid_xattr_entry(const struct wim_xattr_entry *entry, size_t avail)
+{
+       if (avail < sizeof(*entry))
+               return false;
+
+       return entry->name_len > 0 && entry->name_len <= WIM_XATTR_NAME_MAX &&
+               le16_to_cpu(entry->value_len) <= WIM_XATTR_SIZE_MAX &&
+               avail >= xattr_entry_size(entry) &&
+               memchr(entry->name, '\0', entry->name_len) == NULL &&
+               entry->name[entry->name_len] == '\0';
+}
+
 /*
- * On-disk format of an entry in an extended attributes tagged item (wimlib
- * extension).  An xattr item consists of a series of variable-length xattr
- * name/value pairs, each of which begins with this header.
- *
- * Currently this is only used for Linux-style xattrs, but in the future we may
- * use this for Windows-style xattrs too.
+ * On-disk format of each extended attribute entry in a metadata item tagged
+ * with TAG_WIMLIB_LINUX_XATTRS.  This is a deprecated format which wimlib
+ * v1.11-v1.12 used to store extended attributes on Linux (predating the Windows
+ * xattr support in both WIMGAPI and wimlib).  Now we use TAG_XATTRS for both
+ * Windows and Linux xattrs.
  */
-struct wimlib_xattr_entry {
+struct wimlib_xattr_entry_old {
 
-       /* length of xattr name in bytes */
+       /* length of xattr name in bytes, excluding a null terminator */
        le16 name_len;
 
        /* reserved, must be 0 */
@@ -33,17 +91,17 @@ struct wimlib_xattr_entry {
        /* length of xattr value in bytes */
        le32 value_len;
 
-       /* followed by the xattr name with no terminating null */
+       /* followed by the xattr name *without* a null terminator */
        char name[0];
 
-       /* followed by the xattr value with no terminating null */
+       /* followed by the xattr value */
        /* u8 value[0]; */
 
        /* then zero-padded to a 4-byte boundary */
 } _aligned_attribute(4);
 
 static inline size_t
-xattr_entry_size(const struct wimlib_xattr_entry *entry)
+old_xattr_entry_size(const struct wimlib_xattr_entry_old *entry)
 {
        STATIC_ASSERT(sizeof(*entry) == 8);
 
@@ -51,44 +109,34 @@ xattr_entry_size(const struct wimlib_xattr_entry *entry)
                     le32_to_cpu(entry->value_len), 4);
 }
 
-static inline struct wimlib_xattr_entry *
-xattr_entry_next(const struct wimlib_xattr_entry *entry)
+/* minimum is a 1-byte name and an empty value */
+#define OLD_XATTR_ENTRY_MIN_SIZE \
+       (ALIGN(sizeof(struct wimlib_xattr_entry_old) + 1, 4))
+
+static inline struct wimlib_xattr_entry_old *
+old_xattr_entry_next(const struct wimlib_xattr_entry_old *entry)
 {
-       return (void *)entry + xattr_entry_size(entry);
+       return (void *)entry + old_xattr_entry_size(entry);
 }
 
-/* Currently we use the Linux limits when validating xattr names and values */
-#define XATTR_NAME_MAX 255
-#define XATTR_SIZE_MAX 65536
-
 static inline bool
-valid_xattr_entry(const struct wimlib_xattr_entry *entry, size_t avail)
+old_valid_xattr_entry(const struct wimlib_xattr_entry_old *entry, size_t avail)
 {
-       if (avail < sizeof(*entry))
-               return false;
-
-       if (entry->name_len == 0 ||
-           le16_to_cpu(entry->name_len) > XATTR_NAME_MAX)
-               return false;
-
-       if (entry->reserved != 0)
-               return false;
+       u16 name_len;
 
-       if (le32_to_cpu(entry->value_len) > XATTR_SIZE_MAX)
-               return false;
-
-       if (avail < xattr_entry_size(entry))
-               return false;
-
-       if (memchr(entry->name, '\0', le16_to_cpu(entry->name_len)))
+       if (avail < sizeof(*entry))
                return false;
 
-       return true;
+       name_len = le16_to_cpu(entry->name_len);
+       return name_len > 0 && name_len <= WIM_XATTR_NAME_MAX &&
+               le32_to_cpu(entry->value_len) <= WIM_XATTR_SIZE_MAX &&
+               avail >= old_xattr_entry_size(entry) &&
+               memchr(entry->name, '\0', name_len) == NULL;
 }
 
-/* Is the xattr of the specified name security-related? */
+/* Is the xattr of the specified name security-related on Linux? */
 static inline bool
-is_security_xattr(const char *name)
+is_linux_security_xattr(const char *name)
 {
 #define XATTR_SECURITY_PREFIX "security."
 #define XATTR_SYSTEM_PREFIX "system."
@@ -104,23 +152,49 @@ is_security_xattr(const char *name)
 }
 
 static inline const void *
-inode_get_linux_xattrs(const struct wim_inode *inode, u32 *len_ret)
+inode_get_xattrs(const struct wim_inode *inode, u32 *len_ret)
+{
+       return inode_get_tagged_item(inode, TAG_XATTRS,
+                                    XATTR_ENTRY_MIN_SIZE, len_ret);
+}
+
+static inline const void *
+inode_get_xattrs_old(const struct wim_inode *inode, u32 *len_ret)
+{
+       return inode_get_tagged_item(inode, TAG_WIMLIB_LINUX_XATTRS,
+                                    OLD_XATTR_ENTRY_MIN_SIZE, len_ret);
+}
+
+static inline const void *
+inode_get_linux_xattrs(const struct wim_inode *inode, u32 *len_ret,
+                      bool *is_old_format_ret)
 {
-       return inode_get_tagged_item(inode, TAG_WIMLIB_LINUX_XATTRS, 0,
-                                    len_ret);
+       const void *entries;
+
+       entries = inode_get_xattrs(inode, len_ret);
+       if (entries) {
+               *is_old_format_ret = false;
+               return entries;
+       }
+       entries = inode_get_xattrs_old(inode, len_ret);
+       if (entries) {
+               *is_old_format_ret = true;
+               return entries;
+       }
+       return NULL;
 }
 
 static inline bool
-inode_has_linux_xattrs(const struct wim_inode *inode)
+inode_has_xattrs(const struct wim_inode *inode)
 {
-       return inode_get_linux_xattrs(inode, NULL) != NULL;
+       return inode_get_xattrs(inode, NULL) != NULL ||
+              inode_get_xattrs_old(inode, NULL) != NULL;
 }
 
 static inline bool
-inode_set_linux_xattrs(struct wim_inode *inode, const void *entries, u32 len)
+inode_set_xattrs(struct wim_inode *inode, const void *entries, u32 len)
 {
-       return inode_set_tagged_item(inode, TAG_WIMLIB_LINUX_XATTRS,
-                                    entries, len);
+       return inode_set_tagged_item(inode, TAG_XATTRS, entries, len);
 }
 
 #endif /* _WIMLIB_XATTR_H  */