]> wimlib.net Git - wimlib/commitdiff
Recognize tagged metadata items and use for UNIX data
authorEric Biggers <ebiggers3@gmail.com>
Fri, 23 May 2014 01:39:31 +0000 (20:39 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Fri, 23 May 2014 05:04:43 +0000 (00:04 -0500)
This is undocumented, but the Microsoft implementation seems to allow
variable-length, tagged metadata items to be appended to WIM dentries.
Currently it uses them for Object IDs, which DISM (Windows 8.1) will
backup and restore by default.

This commit adds support for these items, so they can be read and written
unmodified.

In addition, for our UNIX data extension, instead of storing the UNIX
data in the reserved fields of the dentry or in alternate data streams,
store it in a custom tagged item with a randomly chosen tag.  This is
perhaps the best choice compatibility-wise.

12 files changed:
Makefile.am
NEWS
include/wimlib/inode.h
include/wimlib/unix_data.h
src/dentry.c
src/extract.c
src/inode.c
src/iterate_dir.c
src/mount_image.c
src/tagged_items.c [new file with mode: 0644]
src/unix_apply.c
src/unix_capture.c

index 1ff845a29aec53ecbc77f2c0a27438565f4e28db..7591fb623903bc68f34b8a7984abe29d23be0e1c 100644 (file)
@@ -63,6 +63,7 @@ libwim_la_SOURCES =           \
        src/sha1.c              \
        src/split.c             \
        src/reparse.c           \
+       src/tagged_items.c      \
        src/template.c          \
        src/textfile.c          \
        src/timestamp.c         \
diff --git a/NEWS b/NEWS
index 1c78f5336b74e874195e0dcee4aa06ca7408f346..b6125877f73233847ce313abab49c809bb06f037 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -18,6 +18,9 @@ Version 1.6.3-BETA:
        --unix-data using wimlib v1.6.2, then re-capture them with --unix-data
        using this version.
 
+       wimlib now understands tagged metadata items, such as object IDs, that
+       can be stored in WIM directory entries.
+
        Removed the --hardlink and --symlink options to wimapply, since I don't
        think they are too useful and they got in the way of improving the code.
 
index 9a94ce2fd8adff6a59da17b722c728e29b5f2c71..8c6aa95fef8cdccb05c16dd759e804000b26b392 100644 (file)
@@ -5,7 +5,6 @@
 #include "wimlib/list.h"
 #include "wimlib/lookup_table.h"
 #include "wimlib/sha1.h"
-#include "wimlib/unix_data.h"
 
 #include <string.h>
 
@@ -107,6 +106,15 @@ struct wim_inode {
         * entries for this inode.  */
        struct wim_ads_entry *i_ads_entries;
 
+       /* If not NULL, a pointer to the extra data that was read from the
+        * dentry.  This should be a series of tagged items, each of which
+        * represents a bit of extra metadata, such as the file's object ID.
+        * See tagged_items.c for more information.  */
+       void *i_extra;
+
+       /* Size of @i_extra buffer in bytes.  If 0, there is no extra data.  */
+       size_t i_extra_size;
+
        /* Creation time, last access time, and last write time for this inode, in
         * 100-nanosecond intervals since 12:00 a.m UTC January 1, 1601.  They
         * should correspond to the times gotten by calling GetFileTime() on
@@ -142,9 +150,6 @@ struct wim_inode {
         * wim_dentry_on_disk'.  */
        u64 i_ino;
 
-       /* UNIX data (wimlib extension)  */
-       struct wimlib_unix_data i_unix_data;
-
        union {
                /* Device number, used only during image capture, so we can
                 * identify hard linked files by the combination of inode number
@@ -344,12 +349,6 @@ ads_entry_is_named_stream(const struct wim_ads_entry *entry)
        return entry->stream_name_nbytes != 0;
 }
 
-static inline bool
-inode_has_unix_data(const struct wim_inode *inode)
-{
-       return inode->i_unix_data.mode != 0;
-}
-
 /* Is the inode a directory?
  * This doesn't count directories with reparse data.
  * wimlib only allows inodes of this type to have children.
index 186214b9168ba5e4e1d09d57ea5f0e21384d876e..6432369533acab7ee0c023bf313d0a0ea5fa99e2 100644 (file)
@@ -7,14 +7,25 @@ struct wimlib_unix_data {
        u32 uid;
        u32 gid;
        u32 mode;
-       u32 reserved;
 };
 
-struct wimlib_unix_data_disk {
-       le32 uid;
-       le32 gid;
-       le32 mode;
-       le32 reserved;
-};
+struct wim_inode;
+
+extern bool
+inode_has_unix_data(const struct wim_inode *inode);
+
+extern bool
+inode_get_unix_data(const struct wim_inode *inode,
+                   struct wimlib_unix_data *unix_data);
+
+#define UNIX_DATA_UID  0x1
+#define UNIX_DATA_GID  0x2
+#define UNIX_DATA_MODE 0x4
+
+#define UNIX_DATA_ALL  (UNIX_DATA_UID | UNIX_DATA_GID | UNIX_DATA_MODE)
+
+extern bool
+inode_set_unix_data(struct wim_inode *inode, u32 uid, u32 gid, u32 mode,
+                   int which);
 
 #endif /* _WIMLIB_UNIX_DATA_H  */
index 42bc05ea58df5da6791fe5880f70633ea15b13fe..2dcc6167164d7d063adaade8c72163f62a4ec093 100644 (file)
@@ -81,14 +81,8 @@ struct wim_dentry_on_disk {
        le64 subdir_offset;
 
        /* Reserved fields */
-       /* As an extension, wimlib can store UNIX data here.  */
-       union {
-               struct {
-                       le64 unused_1;
-                       le64 unused_2;
-               };
-               struct wimlib_unix_data_disk unix_data;
-       };
+       le64 unused_1;
+       le64 unused_2;
 
        /* Creation time, last access time, and last write time, in
         * 100-nanosecond intervals since 12:00 a.m UTC January 1, 1601.  They
@@ -189,6 +183,9 @@ struct wim_dentry_on_disk {
        /* Followed by variable length short name, in UTF16-LE, if
         * short_name_nbytes != 0.  Includes null terminator. */
        /*utf16lechar short_name[];*/
+
+       /* And optionally followed by a variable-length series of tagged items;
+        * see tagged_items.c.  */
 } _packed_attribute;
 
 /* Calculates the unaligned length, in bytes, of an on-disk WIM dentry that has
@@ -206,9 +203,9 @@ dentry_correct_length_unaligned(u16 file_name_nbytes, u16 short_name_nbytes)
 }
 
 /* Calculates the unaligned length, in bytes, of an on-disk WIM dentry, based on
- * the file name length and short name length.  Note that dentry->length is
- * ignored; also, this excludes any alternate data stream entries that may
- * follow the dentry. */
+ * the file name length, short name length, and optional tagged items.  Note
+ * that dentry->length is ignored; also, this excludes any alternate data stream
+ * entries that may follow the dentry.  */
 static u64
 dentry_correct_length_aligned(const struct wim_dentry *dentry)
 {
@@ -216,6 +213,12 @@ dentry_correct_length_aligned(const struct wim_dentry *dentry)
 
        len = dentry_correct_length_unaligned(dentry->file_name_nbytes,
                                              dentry->short_name_nbytes);
+
+       if (dentry->d_inode->i_extra_size) {
+               len = (len + 7) & ~7;
+               len += dentry->d_inode->i_extra_size;
+       }
+
        return (len + 7) & ~7;
 }
 
@@ -1138,6 +1141,21 @@ unlink_dentry(struct wim_dentry *dentry)
        list_del(&dentry->d_ci_conflict_list);
 }
 
+static int
+read_extra_data(const u8 *p, const u8 *end, struct wim_inode *inode)
+{
+       while (((uintptr_t)p & 7) && p < end)
+               p++;
+
+       if (unlikely(p < end)) {
+               inode->i_extra = memdup(p, end - p);
+               if (!inode->i_extra)
+                       return WIMLIB_ERR_NOMEM;
+               inode->i_extra_size = end - p;
+       }
+       return 0;
+}
+
 /* Reads a WIM directory entry, including all alternate data stream entries that
  * follow it, from the WIM image's metadata resource.  */
 static int
@@ -1212,12 +1230,6 @@ read_dentry(const u8 * restrict buf, size_t buf_len,
        inode->i_attributes = le32_to_cpu(disk_dentry->attributes);
        inode->i_security_id = le32_to_cpu(disk_dentry->security_id);
        dentry->subdir_offset = le64_to_cpu(disk_dentry->subdir_offset);
-
-       inode->i_unix_data.uid = le32_to_cpu(disk_dentry->unix_data.uid);
-       inode->i_unix_data.gid = le32_to_cpu(disk_dentry->unix_data.gid);
-       inode->i_unix_data.mode = le32_to_cpu(disk_dentry->unix_data.mode);
-       inode->i_unix_data.reserved = le32_to_cpu(disk_dentry->unix_data.reserved);
-
        inode->i_creation_time = le64_to_cpu(disk_dentry->creation_time);
        inode->i_last_access_time = le64_to_cpu(disk_dentry->last_access_time);
        inode->i_last_write_time = le64_to_cpu(disk_dentry->last_write_time);
@@ -1300,6 +1312,12 @@ read_dentry(const u8 * restrict buf, size_t buf_len,
                p += short_name_nbytes + 2;
        }
 
+       /* Read extra data at end of dentry (but before alternate data stream
+        * entries).  This may contain tagged items.  */
+       ret = read_extra_data(p, &buf[offset + dentry->length], inode);
+       if (ret)
+               goto err_free_dentry;
+
        /* Align the dentry length.  */
        dentry->length = (dentry->length + 7) & ~7;
 
@@ -1569,10 +1587,8 @@ write_dentry(const struct wim_dentry * restrict dentry, u8 * restrict p)
 
        /* UNIX data uses the two 8-byte reserved fields.  So if no UNIX data
         * exists, they get set to 0, just as we would do anyway.  */
-       disk_dentry->unix_data.uid = cpu_to_le32(inode->i_unix_data.uid);
-       disk_dentry->unix_data.gid = cpu_to_le32(inode->i_unix_data.gid);
-       disk_dentry->unix_data.mode = cpu_to_le32(inode->i_unix_data.mode);
-       disk_dentry->unix_data.reserved = cpu_to_le32(inode->i_unix_data.reserved);
+       disk_dentry->unused_1 = cpu_to_le64(0);
+       disk_dentry->unused_2 = cpu_to_le64(0);
 
        disk_dentry->creation_time = cpu_to_le64(inode->i_creation_time);
        disk_dentry->last_access_time = cpu_to_le64(inode->i_last_access_time);
@@ -1612,6 +1628,13 @@ write_dentry(const struct wim_dentry * restrict dentry, u8 * restrict p)
        while ((uintptr_t)p & 7)
                *p++ = 0;
 
+       if (inode->i_extra_size) {
+               /* Extra tagged items --- not usually present.  */
+               p = mempcpy(p, inode->i_extra, inode->i_extra_size);
+               while ((uintptr_t)p & 7)
+                       *p++ = 0;
+       }
+
        disk_dentry->length = cpu_to_le64(p - orig_p);
 
        if (use_dummy_stream) {
index 3adbca342ddfa65e50f61e9e11ca30be5c16fcc4..138623b630da38bfb86331c932132d8a94f8073e 100644 (file)
@@ -53,6 +53,7 @@
 #include "wimlib/reparse.h"
 #include "wimlib/resource.h"
 #include "wimlib/security.h"
+#include "wimlib/unix_data.h"
 #ifdef __WIN32__
 #  include "wimlib/win32.h" /* for realpath() equivalent */
 #endif
index 9eab0d7b534ecb2e3f29b90997ca700b6268c50b..57d92fb265b0cbbb2429636f7cdc8d5a95073ba3 100644 (file)
@@ -108,6 +108,8 @@ free_inode(struct wim_inode *inode)
                        destroy_ads_entry(&inode->i_ads_entries[i]);
                FREE(inode->i_ads_entries);
        }
+       if (inode->i_extra)
+               FREE(inode->i_extra);
        /* HACK: This may instead delete the inode from i_list, but hlist_del()
         * behaves the same as list_del(). */
        if (!hlist_unhashed(&inode->i_hlist))
index dc953c75ac9d6448fc04158733b635600c182e9f..c295dd1858f03af0829583988082bca7e246a349 100644 (file)
@@ -36,6 +36,7 @@
 #include "wimlib/paths.h"
 #include "wimlib/security.h"
 #include "wimlib/timestamp.h"
+#include "wimlib/unix_data.h"
 #include "wimlib/util.h"
 #include "wimlib/wim.h"
 
@@ -48,6 +49,7 @@ init_wimlib_dentry(struct wimlib_dir_entry *wdentry, struct wim_dentry *dentry,
        const struct wim_inode *inode = dentry->d_inode;
        struct wim_lookup_table_entry *lte;
        const u8 *hash;
+       struct wimlib_unix_data unix_data;
 
        ret = utf16le_get_tstr(dentry->file_name, dentry->file_name_nbytes,
                               &wdentry->filename, &dummy);
@@ -81,11 +83,11 @@ init_wimlib_dentry(struct wimlib_dir_entry *wdentry, struct wim_dentry *dentry,
        wdentry->creation_time = wim_timestamp_to_timespec(inode->i_creation_time);
        wdentry->last_write_time = wim_timestamp_to_timespec(inode->i_last_write_time);
        wdentry->last_access_time = wim_timestamp_to_timespec(inode->i_last_access_time);
-
-       wdentry->unix_uid = inode->i_unix_data.uid;
-       wdentry->unix_gid = inode->i_unix_data.gid;
-       wdentry->unix_mode = inode->i_unix_data.mode;
-       wdentry->unix_reserved = inode->i_unix_data.reserved;
+       if (inode_get_unix_data(inode, &unix_data)) {
+               wdentry->unix_uid = unix_data.uid;
+               wdentry->unix_gid = unix_data.gid;
+               wdentry->unix_mode = unix_data.mode;
+       }
 
        lte = inode_unnamed_lte(inode, wim->lookup_table);
        if (lte) {
index e1ff886f583d89298eacd851e3da8d61bf528dd6..169f3d3bf967c66c5ab44630feecec2373274530 100644 (file)
@@ -50,6 +50,7 @@
 #include "wimlib/reparse.h"
 #include "wimlib/resource.h"
 #include "wimlib/timestamp.h"
+#include "wimlib/unix_data.h"
 #include "wimlib/version.h"
 #include "wimlib/write.h"
 #include "wimlib/xml.h"
@@ -342,9 +343,15 @@ create_dentry(struct fuse_context *fuse_ctx, const char *path,
        new->d_inode->i_attributes = attributes;
 
        if (wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA) {
-               new->d_inode->i_unix_data.uid = fuse_ctx->uid;
-               new->d_inode->i_unix_data.gid = fuse_ctx->gid;
-               new->d_inode->i_unix_data.mode = fuse_mask_mode(mode, fuse_ctx);
+               if (!inode_set_unix_data(new->d_inode,
+                                        fuse_ctx->uid,
+                                        fuse_ctx->gid,
+                                        fuse_mask_mode(mode, fuse_ctx),
+                                        UNIX_DATA_ALL))
+               {
+                       free_dentry(new);
+                       return -ENOMEM;
+               }
        }
        dentry_add_child(parent, new);
        list_add_tail(&new->d_inode->i_list, wimfs_ctx->image_inode_list);
@@ -410,14 +417,15 @@ inode_to_stbuf(const struct wim_inode *inode,
               struct stat *stbuf)
 {
        const struct wimfs_context *ctx = wimfs_get_context();
+       struct wimlib_unix_data unix_data;
 
        memset(stbuf, 0, sizeof(struct stat));
        if ((ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA) &&
-           inode_has_unix_data(inode))
+           inode_get_unix_data(inode, &unix_data))
        {
-               stbuf->st_uid = inode->i_unix_data.uid;
-               stbuf->st_gid = inode->i_unix_data.gid;
-               stbuf->st_mode = inode->i_unix_data.mode;
+               stbuf->st_uid = unix_data.uid;
+               stbuf->st_gid = unix_data.gid;
+               stbuf->st_mode = unix_data.mode;
        } else {
                stbuf->st_uid = ctx->default_uid;
                stbuf->st_gid = ctx->default_gid;
@@ -1621,11 +1629,10 @@ wimfs_chmod(const char *path, mode_t mask)
 
        inode = dentry->d_inode;
 
-       if (!inode_has_unix_data(inode)) {
-               inode->i_unix_data.uid = ctx->default_uid;
-               inode->i_unix_data.gid = ctx->default_gid;
-       }
-       inode->i_unix_data.mode = mask;
+       if (!inode_set_unix_data(inode, ctx->default_uid,
+                                ctx->default_gid, mask, UNIX_DATA_MODE))
+               return -ENOMEM;
+
        return 0;
 }
 
@@ -1635,6 +1642,7 @@ wimfs_chown(const char *path, uid_t uid, gid_t gid)
        struct wim_dentry *dentry;
        struct wim_inode *inode;
        struct wimfs_context *ctx = wimfs_get_context();
+       int which;
        int ret;
 
        if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA))
@@ -1647,10 +1655,23 @@ wimfs_chown(const char *path, uid_t uid, gid_t gid)
 
        inode = dentry->d_inode;
 
-       if (!inode_has_unix_data(inode))
-               inode->i_unix_data.mode = inode_default_unix_mode(inode);
-       inode->i_unix_data.uid = uid;
-       inode->i_unix_data.gid = gid;
+       which = 0;
+
+       if (uid != (uid_t)-1)
+               which |= UNIX_DATA_UID;
+       else
+               uid = ctx->default_uid;
+
+       if (gid != (gid_t)-1)
+               which |= UNIX_DATA_GID;
+       else
+               gid = ctx->default_gid;
+
+
+       if (!inode_set_unix_data(inode, uid, gid,
+                                inode_default_unix_mode(inode), which))
+               return -ENOMEM;
+
        return 0;
 }
 
diff --git a/src/tagged_items.c b/src/tagged_items.c
new file mode 100644 (file)
index 0000000..3a12974
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * tagged_items.c
+ *
+ * Support for tagged metadata items that can be appended to WIM directory
+ * entries.
+ */
+
+/*
+ * Copyright (C) 2014 Eric Biggers
+ *
+ * This file is part of wimlib, a library for working with WIM files.
+ *
+ * wimlib is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with wimlib; if not, see http://www.gnu.org/licenses/.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include "wimlib/endianness.h"
+#include "wimlib/inode.h"
+#include "wimlib/types.h"
+#include "wimlib/unix_data.h"
+
+/* Used by the Microsoft implementation.  */
+#define TAG_OBJECT_ID          0x00000001
+
+/* Random number that we'll use for tagging our UNIX data items.  */
+#define TAG_WIMLIB_UNIX_DATA   0x337DD873
+
+/* Header that begins each tagged metadata item in the metadata resource  */
+struct tagged_item_header {
+
+       /* Unique identifier for this item.  */
+       le32 tag;
+
+       /* Size of the data of this tagged item, in bytes.  This includes this
+        * header and should be a multiple of 8.
+        *
+        * (Actually, the MS implementation seems to round this up to an 8 byte
+        * boundary when calculating the offset to the next tagged item, but
+        * uses this length unmodified when validating the item.  We might as
+        * well do the same.)  */
+       le32 length;
+
+       /* Variable length data  */
+       u8 data[];
+};
+
+struct object_id_disk {
+       u8 object_id[16];
+       u8 birth_volume_id[16];
+       u8 birth_object_id[16];
+       u8 domain_id[16];
+};
+
+struct wimlib_unix_data_disk {
+       le32 uid;
+       le32 gid;
+       le32 mode;
+       le32 reserved;
+};
+
+/* Retrieves the first tagged item with the specified tag and minimum length
+ * from the WIM inode.  Returns a pointer to the tagged data, which can be read
+ * and/or modified in place.  Or, if no matching tagged item is found, returns
+ * NULL.  */
+static void *
+inode_get_tagged_item(const struct wim_inode *inode,
+                     u32 desired_tag, u32 min_data_len)
+{
+       size_t minlen_with_hdr = sizeof(struct tagged_item_header) + min_data_len;
+       size_t len_remaining = inode->i_extra_size;
+       u8 *p = inode->i_extra;
+
+       /* Iterate through the tagged items.  */
+       while (len_remaining >= minlen_with_hdr) {
+               struct tagged_item_header *hdr;
+               u32 tag;
+               u32 len;
+
+               hdr = (struct tagged_item_header *)p;
+               tag = le32_to_cpu(hdr->tag);
+               len = le32_to_cpu(hdr->length);
+
+               if (tag == desired_tag && len >= min_data_len)
+                       return hdr->data;
+
+               len = (len + 7) & ~7;
+               if (len >= len_remaining)
+                       return NULL;
+               len_remaining -= len;
+               p = hdr->data + len;
+       }
+       return NULL;
+}
+
+/* Adds a tagged item to a WIM inode and returns a pointer to its uninitialized
+ * data, which must be initialized in-place by the caller.  */
+static void *
+inode_add_tagged_item(struct wim_inode *inode, u32 tag, u32 len)
+{
+       size_t itemsize;
+       size_t newsize;
+       u8 *buf;
+       struct tagged_item_header *hdr;
+
+       /* We prepend the item instead of appending it because it's easier.  */
+
+       itemsize = sizeof(struct tagged_item_header) + len;
+       newsize = itemsize + inode->i_extra_size;
+
+       buf = MALLOC(newsize);
+       if (!buf)
+               return NULL;
+
+       if (inode->i_extra_size) {
+               memcpy(buf + itemsize, inode->i_extra, inode->i_extra_size);
+               FREE(inode->i_extra);
+       }
+       inode->i_extra = buf;
+       inode->i_extra_size = newsize;
+
+       hdr = (struct tagged_item_header *)buf;
+       hdr->tag = cpu_to_le32(tag);
+       hdr->length = cpu_to_le32(len);
+       return hdr->data;
+}
+
+static inline struct wimlib_unix_data_disk *
+inode_get_unix_data_disk(const struct wim_inode *inode)
+{
+       return inode_get_tagged_item(inode, TAG_WIMLIB_UNIX_DATA,
+                                    sizeof(struct wimlib_unix_data_disk));
+}
+
+static inline struct wimlib_unix_data_disk *
+inode_add_unix_data_disk(struct wim_inode *inode)
+{
+       return inode_add_tagged_item(inode, TAG_WIMLIB_UNIX_DATA,
+                                    sizeof(struct wimlib_unix_data_disk));
+}
+
+/* Returns %true if the specified WIM inode has UNIX data; otherwise %false.
+ * This is a wimlib extension.  */
+bool
+inode_has_unix_data(const struct wim_inode *inode)
+{
+       return inode_get_unix_data_disk(inode) != NULL;
+}
+
+/* Retrieves UNIX data from the specified WIM inode.
+ * This is a wimlib extension.
+ *
+ * Returns %true and fills @unix_data if the inode has UNIX data.
+ * Otherwise returns %false.  */
+bool
+inode_get_unix_data(const struct wim_inode *inode,
+                   struct wimlib_unix_data *unix_data)
+{
+       const struct wimlib_unix_data_disk *p;
+
+       p = inode_get_unix_data_disk(inode);
+       if (!p)
+               return false;
+
+       unix_data->uid = le32_to_cpu(p->uid);
+       unix_data->gid = le32_to_cpu(p->gid);
+       unix_data->mode = le32_to_cpu(p->mode);
+       return true;
+}
+
+/* Sets UNIX data on the specified WIM inode.
+ * This is a wimlib extension.
+ *
+ * Callers must specify all of @uid, @gid, and @mode.  If the inode does not yet
+ * have UNIX data, it is given these values.  Otherwise, only the values that
+ * also have the corresponding flags in @which set are changed.
+ *
+ * Returns %true if successful, %false if failed (out of memory).  */
+bool
+inode_set_unix_data(struct wim_inode *inode, u32 uid, u32 gid, u32 mode,
+                   int which)
+{
+       struct wimlib_unix_data_disk *p;
+
+       p = inode_get_unix_data_disk(inode);
+       if (!p) {
+               p = inode_add_unix_data_disk(inode);
+               if (!p)
+                       return false;
+               p->reserved = cpu_to_le32(0);
+               which = UNIX_DATA_UID | UNIX_DATA_GID | UNIX_DATA_MODE;
+       }
+       if (which & UNIX_DATA_UID)
+               p->uid = cpu_to_le32(uid);
+       if (which & UNIX_DATA_GID)
+               p->gid = cpu_to_le32(gid);
+       if (which & UNIX_DATA_MODE)
+               p->mode = cpu_to_le32(mode);
+       return true;
+}
index bf9c2911d57630ed2f847f68e4a35df9e00d92bb..40dc9edf701a1a9285632f24504be666103055de 100644 (file)
@@ -31,6 +31,7 @@
 #include "wimlib/file_io.h"
 #include "wimlib/reparse.h"
 #include "wimlib/timestamp.h"
+#include "wimlib/unix_data.h"
 
 #include <errno.h>
 #include <fcntl.h>
@@ -252,16 +253,17 @@ unix_set_metadata(int fd, const struct wim_inode *inode,
                  const char *path, struct unix_apply_ctx *ctx)
 {
        int ret;
+       struct wimlib_unix_data unix_data;
 
        if (fd < 0 && !path)
                path = unix_build_inode_extraction_path(inode, ctx);
 
        if ((ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_UNIX_DATA)
-           && inode_has_unix_data(inode))
+           && inode_get_unix_data(inode, &unix_data))
        {
-               u32 uid = inode->i_unix_data.uid;
-               u32 gid = inode->i_unix_data.gid;
-               u32 mode = inode->i_unix_data.mode;
+               u32 uid = unix_data.uid;
+               u32 gid = unix_data.gid;
+               u32 mode = unix_data.mode;
 
                ret = unix_set_owner_and_group(fd, path, uid, gid);
                if (ret) {
index c6444d3e38dff8bffdb8e54fc3cdcf4de0ed171d..a72d3ad3fc8f033ab5910aeb4bf80ec495451be2 100644 (file)
@@ -40,6 +40,7 @@
 #include "wimlib/lookup_table.h"
 #include "wimlib/reparse.h"
 #include "wimlib/timestamp.h"
+#include "wimlib/unix_data.h"
 
 #ifdef HAVE_FDOPENDIR
 #  define my_fdopendir(dirfd_p) fdopendir(*(dirfd_p))
@@ -386,9 +387,12 @@ unix_build_dentry_tree_recursive(struct wim_dentry **tree_ret,
 #endif
        inode->i_resolved = 1;
        if (params->add_flags & WIMLIB_ADD_FLAG_UNIX_DATA) {
-               inode->i_unix_data.uid = stbuf.st_uid;
-               inode->i_unix_data.gid = stbuf.st_gid;
-               inode->i_unix_data.mode = stbuf.st_mode;
+               if (!inode_set_unix_data(inode, stbuf.st_uid, stbuf.st_gid,
+                                        stbuf.st_mode, UNIX_DATA_ALL))
+               {
+                       ret = WIMLIB_ERR_NOMEM;
+                       goto out;
+               }
        }
 
        if (params->add_flags & WIMLIB_ADD_FLAG_ROOT) {