include/wimlib/wim.h \
include/wimlib/write.h \
include/wimlib/x86_cpu_features.h \
+ include/wimlib/xattr.h \
include/wimlib/xml.h \
include/wimlib/xml_windows.h \
include/wimlib/xpress_constants.h
# Useful functions which we can do without.
AC_CHECK_FUNCS([futimens utimensat flock mempcpy \
- openat fstatat readlinkat fdopendir posix_fallocate])
+ openat fstatat readlinkat fdopendir posix_fallocate \
+ llistxattr lgetxattr fsetxattr])
# Header checks, most of which are only here to satisfy conditional includes
# made by the libntfs-3g headers.
unsigned long object_ids;
unsigned long timestamps;
unsigned long case_sensitive_filenames;
+ unsigned long linux_xattrs;
};
struct blob_descriptor;
* as well as the encrypted data of all the file's data streams. */
STREAM_TYPE_EFSRPC_RAW_DATA,
+ /* Extended attributes originating from Linux (wimlib extension) */
+ STREAM_TYPE_LINUX_XATTR,
+
/* Stream type could not be determined */
STREAM_TYPE_UNKNOWN,
};
* one such stream, and it should be unnamed. However, it is possible for an
* inode to have both a reparse point stream and an unnamed data stream, and
* even named data streams as well.
+ *
+ * On Linux, wimlib now also supports storing and restoring extended attributes.
+ * For this an unnamed stream of type STREAM_TYPE_LINUX_XATTR is used.
*/
struct wim_inode_stream {
/* [wimlib extension] Standard UNIX metadata: uid, gid, mode, and rdev */
#define TAG_WIMLIB_UNIX_DATA 0x337DD873
+/* [wimlib extension] Hash of stream containing Linux-style xattrs */
+#define TAG_WIMLIB_LINUX_XATTR_HASH 0x337DD874
+
extern bool
inode_set_tagged_data(struct wim_inode *inode, u32 tag,
const void *data, u32 len);
--- /dev/null
+#ifndef _WIMLIB_XATTR_H
+#define _WIMLIB_XATTR_H
+
+#include "wimlib/endianness.h"
+#include "wimlib/sha1.h"
+#include "wimlib/tagged_items.h"
+#include "wimlib/util.h"
+
+#undef HAVE_XATTR_SUPPORT
+#if defined(HAVE_SYS_XATTR_H) && defined(HAVE_LLISTXATTR) && \
+ defined(HAVE_LGETXATTR) && defined(HAVE_FSETXATTR)
+# define HAVE_XATTR_SUPPORT 1
+#endif
+
+/*
+ * On-disk format of an entry in an extended attribute stream (wimlib
+ * extension). An xattr stream consists of a series of variable-length xattr
+ * entries, each of which begins with this entry header.
+ *
+ * Currently this is only used for Linux-style xattrs, but in the future we may
+ * use this for Windows-style xattrs too.
+ */
+struct wimlib_xattr_entry {
+
+ /* length of xattr name in bytes */
+ le16 name_len;
+
+ /* reserved, must be 0 */
+ le16 reserved;
+
+ /* length of xattr value in bytes, not counting padding */
+ le32 value_len;
+
+ /* followed by the name with no terminating null */
+ char name[0];
+
+ /*
+ * directly followed by the value, zero-padded to the next 4-byte
+ * boundary if not already aligned
+ */
+ /* u8 value[0]; */
+};
+
+static inline size_t
+xattr_entry_size(const struct wimlib_xattr_entry *entry)
+{
+ return ALIGN(sizeof(*entry) + le16_to_cpu(entry->name_len) +
+ le32_to_cpu(entry->value_len), 4);
+}
+
+static inline struct wimlib_xattr_entry *
+xattr_entry_next(const struct wimlib_xattr_entry *entry)
+{
+ return (void *)entry + 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)
+{
+ 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;
+
+ if (le32_to_cpu(entry->value_len) > XATTR_SIZE_MAX)
+ return false;
+
+ return avail >= xattr_entry_size(entry);
+}
+
+static inline const u8 *
+inode_get_linux_xattr_hash(const struct wim_inode *inode)
+{
+ return inode_get_tagged_item(inode, TAG_WIMLIB_LINUX_XATTR_HASH,
+ SHA1_HASH_SIZE, NULL);
+}
+
+static inline bool
+inode_has_linux_xattr_hash(const struct wim_inode *inode)
+{
+ return inode_get_linux_xattr_hash(inode) != NULL;
+}
+
+static inline bool
+inode_set_linux_xattr_hash(struct wim_inode *inode, const u8 *hash)
+{
+ return inode_set_tagged_data(inode, TAG_WIMLIB_LINUX_XATTR_HASH,
+ hash, SHA1_HASH_SIZE);
+}
+
+#endif /* _WIMLIB_XATTR_H */
#include "wimlib/endianness.h"
#include "wimlib/metadata.h"
#include "wimlib/paths.h"
+#include "wimlib/xattr.h"
/* On-disk format of a WIM dentry (directory entry), located in the metadata
* resource for a WIM image. */
{
for (unsigned i = 0; i < inode->i_num_streams; i++) {
struct wim_inode_stream *strm = &inode->i_streams[i];
- if (!stream_is_named(strm) && !is_zero_hash(strm->_stream_hash))
+ if (strm->stream_type == STREAM_TYPE_UNKNOWN &&
+ !stream_is_named(strm) && !is_zero_hash(strm->_stream_hash))
{
strm->stream_type = STREAM_TYPE_EFSRPC_RAW_DATA;
return;
for (unsigned i = 0; i < inode->i_num_streams; i++) {
struct wim_inode_stream *strm = &inode->i_streams[i];
+ if (strm->stream_type != STREAM_TYPE_UNKNOWN)
+ continue;
if (stream_is_named(strm)) {
/* Named data stream */
strm->stream_type = STREAM_TYPE_DATA;
u64 *offset_p)
{
const u8 *orig_p = p;
+ const u8 *linux_xattr_hash = inode_get_linux_xattr_hash(inode);
+ unsigned i;
- inode->i_num_streams = 1 + num_extra_streams;
+ inode->i_num_streams = 1 + num_extra_streams +
+ (linux_xattr_hash != NULL);
if (unlikely(inode->i_num_streams > ARRAY_LEN(inode->i_embedded_streams))) {
inode->i_streams = CALLOC(inode->i_num_streams,
inode->i_streams[0].stream_id = 0;
/* Read the extra stream entries */
- for (unsigned i = 1; i < inode->i_num_streams; i++) {
+ for (i = 1; i < 1 + num_extra_streams; i++) {
struct wim_inode_stream *strm;
const struct wim_extra_stream_entry_on_disk *disk_strm;
u64 length;
p += length;
}
- inode->i_next_stream_id = inode->i_num_streams;
+ /* Set up the xattr stream if there is one (wimlib extension) */
+ if (linux_xattr_hash != NULL) {
+ struct wim_inode_stream *strm = &inode->i_streams[i];
+
+ strm->stream_id = i;
+ strm->stream_type = STREAM_TYPE_LINUX_XATTR;
+ strm->stream_name = (utf16lechar *)NO_STREAM_NAME;
+ copy_hash(strm->_stream_hash, linux_xattr_hash);
+ i++;
+ }
+
+ inode->i_next_stream_id = i;
/* Now, assign a type to each stream. Unfortunately this requires
* various hacks because stream types aren't explicitly provided in the
- * WIM on-disk format. */
+ * WIM on-disk format (except for the wimlib-specific xattr stream) */
if (unlikely(inode->i_attributes & FILE_ATTRIBUTE_ENCRYPTED))
assign_stream_types_encrypted(inode);
#include "wimlib/unix_data.h"
#include "wimlib/wim.h"
#include "wimlib/win32.h" /* for realpath() equivalent */
+#include "wimlib/xattr.h"
#include "wimlib/xml.h"
#define WIMLIB_EXTRACT_FLAG_FROM_PIPE 0x80000000
need_stream = true;
}
break;
+ case STREAM_TYPE_LINUX_XATTR:
+ if ((ctx->extract_flags & WIMLIB_EXTRACT_FLAG_UNIX_DATA) &&
+ ctx->supported_features.linux_xattrs)
+ need_stream = true;
+ break;
}
if (need_stream)
return ref_stream(strm, dentry, ctx);
features->unix_data++;
if (inode_has_object_id(inode))
features->object_ids++;
+ if (inode_has_linux_xattr_hash(inode))
+ features->linux_xattrs++;
}
/* Tally features necessary to extract a dentry and the corresponding inode. */
WARNING("Ignoring Windows NT security descriptors of %lu files",
required_features->security_descriptors);
- /* UNIX data. */
+ /* Standard UNIX metadata */
if ((extract_flags & WIMLIB_EXTRACT_FLAG_UNIX_DATA) &&
required_features->unix_data && !supported_features->unix_data)
{
- ERROR("Extraction backend does not support UNIX data!");
+ ERROR("Extraction backend does not support standard UNIX "
+ "metadata (uid/gid/mode/rdev)!");
return WIMLIB_ERR_UNSUPPORTED;
}
if (required_features->unix_data &&
!(extract_flags & WIMLIB_EXTRACT_FLAG_UNIX_DATA))
{
- WARNING("Ignoring UNIX metadata of %lu files",
- required_features->unix_data);
+ WARNING("Ignoring standard UNIX metadata (uid/gid/mode/rdev) "
+ "of %lu files", required_features->unix_data);
+ }
+
+ /* Linux-style extended attributes */
+ if (required_features->linux_xattrs &&
+ (!supported_features->linux_xattrs ||
+ !(extract_flags & WIMLIB_EXTRACT_FLAG_UNIX_DATA)))
+ {
+ WARNING("Ignoring Linux-style extended attributes of %lu files",
+ required_features->linux_xattrs);
}
/* Object IDs. */