Alternate stream entries fixes
authorEric Biggers <ebiggers3@gmail.com>
Sat, 18 Aug 2012 04:59:17 +0000 (23:59 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Sat, 18 Aug 2012 04:59:17 +0000 (23:59 -0500)
src/dentry.c
src/dentry.h
src/extract.c
src/modify.c
src/mount.c

index d3399ac..8551299 100644 (file)
 #include <unistd.h>
 #include <sys/stat.h>
 
+/* Real length of a dentry, including the alternate data stream entries, which
+ * are not included in the dentry->length field... */
+u64 dentry_total_length(const struct dentry *dentry)
+{
+       u64 length = dentry->length;
+       if (dentry->num_ads) {
+               u16 i = 0;
+               do {
+                       length += WIM_ADS_ENTRY_DISK_SIZE + 
+                                 dentry->ads_entries[i].stream_name_len;
+               } while (++i != dentry->num_ads);
+               /* If there are Alternate Stream Entries, we apparently need to
+                * round up to the NEXT 8-byte boundary, even if we are already
+                * aligned on one... */
+               length++;
+       }
+       /* Round to 8 byte boundary. */
+       return (length + 7) & ~7;
+}
 
 /* Transfers file attributes from a `stat' buffer to a struct dentry. */
 void stbuf_to_dentry(const struct stat *stbuf, struct dentry *dentry)
 {
        if (S_ISDIR(stbuf->st_mode))
-               dentry->attributes = WIM_FILE_ATTRIBUTE_DIRECTORY;
+               dentry->attributes = FILE_ATTRIBUTE_DIRECTORY;
        else
-               dentry->attributes = WIM_FILE_ATTRIBUTE_NORMAL;
+               dentry->attributes = FILE_ATTRIBUTE_NORMAL;
 }
 
 /* Transfers file attributes from a struct dentry to a `stat' buffer. */
@@ -210,7 +229,7 @@ void calculate_subdir_offsets(struct dentry *dentry, u64 *subdir_offset_p)
                /* Advance the subdir offset by the amount of space the children
                 * of this dentry take up. */
                do {
-                       *subdir_offset_p += child->length;
+                       *subdir_offset_p += dentry_total_length(child);
                        child = child->next;
                } while (child != dentry->children);
 
@@ -314,21 +333,21 @@ struct file_attr_flag {
        const char *name;
 };
 struct file_attr_flag file_attr_flags[] = {
-       {WIM_FILE_ATTRIBUTE_READONLY,           "READONLY"},
-       {WIM_FILE_ATTRIBUTE_HIDDEN,             "HIDDEN"},
-       {WIM_FILE_ATTRIBUTE_SYSTEM,             "SYSTEM"},
-       {WIM_FILE_ATTRIBUTE_DIRECTORY,          "DIRECTORY"},
-       {WIM_FILE_ATTRIBUTE_ARCHIVE,            "ARCHIVE"},
-       {WIM_FILE_ATTRIBUTE_DEVICE,             "DEVICE"},
-       {WIM_FILE_ATTRIBUTE_NORMAL,             "NORMAL"},
-       {WIM_FILE_ATTRIBUTE_TEMPORARY,          "TEMPORARY"},
-       {WIM_FILE_ATTRIBUTE_SPARSE_FILE,        "SPARSE_FILE"},
-       {WIM_FILE_ATTRIBUTE_REPARSE_POINT,      "REPARSE_POINT"},
-       {WIM_FILE_ATTRIBUTE_COMPRESSED,         "COMPRESSED"},
-       {WIM_FILE_ATTRIBUTE_OFFLINE,            "OFFLINE"},
-       {WIM_FILE_ATTRIBUTE_NOT_CONTENT_INDEXED,"NOT_CONTENT_INDEXED"},
-       {WIM_FILE_ATTRIBUTE_ENCRYPTED,          "ENCRYPTED"},
-       {WIM_FILE_ATTRIBUTE_VIRTUAL,            "VIRTUAL"},
+       {FILE_ATTRIBUTE_READONLY,               "READONLY"},
+       {FILE_ATTRIBUTE_HIDDEN,         "HIDDEN"},
+       {FILE_ATTRIBUTE_SYSTEM,         "SYSTEM"},
+       {FILE_ATTRIBUTE_DIRECTORY,              "DIRECTORY"},
+       {FILE_ATTRIBUTE_ARCHIVE,                "ARCHIVE"},
+       {FILE_ATTRIBUTE_DEVICE,         "DEVICE"},
+       {FILE_ATTRIBUTE_NORMAL,         "NORMAL"},
+       {FILE_ATTRIBUTE_TEMPORARY,              "TEMPORARY"},
+       {FILE_ATTRIBUTE_SPARSE_FILE,    "SPARSE_FILE"},
+       {FILE_ATTRIBUTE_REPARSE_POINT,  "REPARSE_POINT"},
+       {FILE_ATTRIBUTE_COMPRESSED,             "COMPRESSED"},
+       {FILE_ATTRIBUTE_OFFLINE,                "OFFLINE"},
+       {FILE_ATTRIBUTE_NOT_CONTENT_INDEXED,"NOT_CONTENT_INDEXED"},
+       {FILE_ATTRIBUTE_ENCRYPTED,              "ENCRYPTED"},
+       {FILE_ATTRIBUTE_VIRTUAL,                "VIRTUAL"},
 };
 
 /* Prints a directory entry.  @lookup_table is a pointer to the lookup table, or
@@ -343,11 +362,11 @@ int print_dentry(struct dentry *dentry, void *lookup_table)
        printf("Attributes        = 0x%x\n", dentry->attributes);
        for (i = 0; i < ARRAY_LEN(file_attr_flags); i++)
                if (file_attr_flags[i].flag & dentry->attributes)
-                       printf("    WIM_FILE_ATTRIBUTE_%s is set\n",
+                       printf("    FILE_ATTRIBUTE_%s is set\n",
                                file_attr_flags[i].name);
        printf("Security ID       = %d\n", dentry->security_id);
        printf("Subdir offset     = %"PRIu64"\n", dentry->subdir_offset);
-       /*printf("Unused1           = %"PRIu64"\n", dentry->unused1);*/
+       /*printf("Unused1           = 0x%"PRIu64"\n", dentry->unused1);*/
        /*printf("Unused2           = %"PRIu64"\n", dentry->unused2);*/
        printf("Creation Time     = %"PRIu64"\n", dentry->creation_time);
        printf("Last Access Time  = %"PRIu64"\n", dentry->last_access_time);
@@ -356,8 +375,8 @@ int print_dentry(struct dentry *dentry, void *lookup_table)
        printf("Hash              = "); 
        print_hash(dentry->hash); 
        putchar('\n');
-       printf("Reparse Tag       = %u\n", dentry->reparse_tag);
-       printf("Hard Link Group   = %"PRIu64"\n", dentry->hard_link);
+       printf("Reparse Tag       = 0x%"PRIx32"\n", dentry->reparse_tag);
+       printf("Hard Link Group   = 0x%"PRIx64"\n", dentry->hard_link);
        printf("Number of Alternate Data Streams = %hu\n", dentry->num_ads);
        printf("Filename          = \"");
        print_string(dentry->file_name, dentry->file_name_len);
@@ -379,6 +398,15 @@ int print_dentry(struct dentry *dentry, void *lookup_table)
        } else {
                putchar('\n');
        }
+       for (u16 i = 0; i < dentry->num_ads; i++) {
+               printf("[Alternate Stream Entry %u]\n", i);
+               printf("Name = \"%s\"\n", dentry->ads_entries[i].stream_name_utf8);
+               lte = lookup_resource(lookup_table, dentry->ads_entries[i].hash);
+               if (lte)
+                       print_lookup_table_entry(lte, NULL);
+               else
+                       putchar('\n');
+       }
        return 0;
 }
 
@@ -611,40 +639,52 @@ void calculate_dir_tree_statistics(struct dentry *root, struct lookup_table *tab
 }
 
 static int read_ads_entries(const u8 *p, struct dentry *dentry,
-                           unsigned remaining_size)
+                           u64 remaining_size)
 {
        u16 num_ads = dentry->num_ads;
        struct ads_entry *ads_entries = CALLOC(num_ads, sizeof(struct ads_entry));
        int ret;
        if (!ads_entries) {
-               ERROR("Could not allocate memory for %u alternate data stream "
-                     "entries", num_ads);
+               ERROR("Could not allocate memory for %"PRIu16" "
+                     "alternate data stream entries", num_ads);
                return WIMLIB_ERR_NOMEM;
        }
+       DEBUG2("Reading %"PRIu16" alternate data streams "
+              "(remaining size = %"PRIu64")", num_ads, remaining_size);
+
        for (u16 i = 0; i < num_ads; i++) {
                struct ads_entry *cur_entry = &ads_entries[i];
                u64 length;
                size_t utf8_len;
                /* Read the base stream entry, excluding the stream name. */
                if (remaining_size < WIM_ADS_ENTRY_DISK_SIZE) {
-                       ERROR("Stream entries go past end of directory entry");
+                       ERROR("Stream entries go past end of metadata resource");
                        ret = WIMLIB_ERR_INVALID_DENTRY;
                        goto out_free_ads_entries;
                }
                remaining_size -= WIM_ADS_ENTRY_DISK_SIZE;
+               /*print_string(p + 40, 10);*/
+               /*print_byte_field(p, 50);*/
 
                p = get_u64(p, &length); /* ADS entry length */
+
+               DEBUG2("ADS length = %"PRIu64, length);
+
                p += 8; /* Unused */
                p = get_bytes(p, WIM_HASH_SIZE, (u8*)cur_entry->hash);
                p = get_u16(p, &cur_entry->stream_name_len);
+
+               DEBUG2("Stream name length = %u", cur_entry->stream_name_len);
+
                cur_entry->stream_name = NULL;
                cur_entry->stream_name_utf8 = NULL;
 
-               if (remaining_size < cur_entry->stream_name_len) {
-                       ERROR("Stream entries go past end of directory entry");
+               if (remaining_size < cur_entry->stream_name_len + 2) {
+                       ERROR("Stream entries go past end of metadata resource");
                        ret = WIMLIB_ERR_INVALID_DENTRY;
                        goto out_free_ads_entries;
                }
+               remaining_size -= cur_entry->stream_name_len + 2;
 
                cur_entry->stream_name = MALLOC(cur_entry->stream_name_len);
                if (!cur_entry->stream_name) {
@@ -653,10 +693,12 @@ static int read_ads_entries(const u8 *p, struct dentry *dentry,
                }
                p = get_bytes(p, cur_entry->stream_name_len,
                              (u8*)cur_entry->stream_name);
+               p += 2; /* NULL terminator of stream name */
                cur_entry->stream_name_utf8 = utf16_to_utf8(cur_entry->stream_name,
                                                            cur_entry->stream_name_len,
                                                            &utf8_len);
                cur_entry->stream_name_len_utf8 = utf8_len;
+               print_byte_field(p, 16);
 
                if (!cur_entry->stream_name_utf8) {
                        ret = WIMLIB_ERR_NOMEM;
@@ -705,6 +747,7 @@ int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len,
         * terminates the list of sibling directory entries. */
 
        p = get_u64(&metadata_resource[offset], &dentry->length);
+       DEBUG("length = %zu, %zu\n", dentry->length, *(u64*)(&metadata_resource[offset]));
 
        /* A zero length field (really a length of 8, since that's how big the
         * directory entry is...) indicates that this is the end of directory
@@ -736,6 +779,8 @@ int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len,
 
        /* 2 unused fields */
        p += 2 * sizeof(u64);
+       /*p = get_u64(p, &dentry->unused1);*/
+       /*p = get_u64(p, &dentry->unused2);*/
 
        p = get_u64(p, &dentry->creation_time);
        p = get_u64(p, &dentry->last_access_time);
@@ -743,11 +788,29 @@ int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len,
 
        p = get_bytes(p, WIM_HASH_SIZE, dentry->hash);
        
-       p = get_u32(p, &dentry->reparse_tag);
+       /*
+        * I don't know what's going on here.  It seems like M$ screwed up the
+        * reparse points, then put the fields in the same place and didn't
+        * document it.  The WIM_HDR_FLAG_RP_FIX flag in the WIM header might
+        * have something to do with this, but it's not documented.
+        */
+       if (dentry->attributes & FILE_ATTRIBUTE_REPARSE_POINT) {
+               /* ??? */
+               u32 u1, u2;
+               p = get_u32(p, &u1);
+               /*p += 4;*/
+               p = get_u32(p, &dentry->reparse_tag);
+               p = get_u32(p, &u2);
+               /*p += 4;*/
+               dentry->hard_link = (u64)(u1) | ((u64)(u2) << 32);
+       } else {
+               p = get_u32(p, &dentry->reparse_tag);
+               p = get_u64(p, &dentry->hard_link);
+       }
 
-       /* The reparse_reserved field does not actually exist. */
+       /* By the way, the reparse_reserved field does not actually exist (at
+        * least when the file is not a reparse point) */
 
-       p = get_u64(p, &dentry->hard_link);
        
        p = get_u16(p, &dentry->num_ads);
 
@@ -799,11 +862,44 @@ int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len,
                goto out_free_file_name_utf8;
        }
 
-       get_bytes(p, short_name_len, short_name);
+       p = get_bytes(p, short_name_len, short_name);
+
+       /* Some directory entries inexplicibly have a little over 70 bytes of
+        * extra data.  The exact amount of data seems to be 72 bytes, but it is
+        * aligned on the next 8-byte boundary.  Here's an example of the
+        * aligned data:
+        *
+        * 01000000400000006c786bbac58ede11b0bb00261870892ab6adb76fe63a3
+        * e468fca86530d2effa16c786bbac58ede11b0bb00261870892a0000000000
+        * 0000000000000000000000
+        *
+        * Here's one interpretation of how the data is laid out.
+        *
+        * struct unknown {
+        *      u32 field1; (always 0x00000001)
+        *      u32 field2; (always 0x40000000)
+        *      u16 field3;
+        *      u32 field4;
+        *      u32 field5;
+        *      u32 field6;
+        *      u8  data[48]; (???)
+        *      u64 reserved1; (always 0)
+        *      u64 reserved2; (always 0)
+        * };*/
+#if 0
+       if (dentry->length - calculated_size >= WIM_ADS_ENTRY_DISK_SIZE) {
+               printf("%s: %lu / %lu (", file_name_utf8, 
+                               calculated_size, dentry->length);
+               print_string(p + WIM_ADS_ENTRY_DISK_SIZE, dentry->length - calculated_size - WIM_ADS_ENTRY_DISK_SIZE);
+               puts(")");
+               print_byte_field(p, dentry->length - calculated_size);
+               putchar('\n');
+       }
+#endif
 
        if (dentry->num_ads != 0) {
                ret = read_ads_entries(p, dentry,
-                                      dentry->length - calculated_size);
+                                      metadata_resource_len - offset - calculated_size);
                if (ret != 0)
                        goto out_free_short_name;
        }
@@ -845,10 +941,7 @@ static u8 *write_dentry(const struct dentry *dentry, u8 *p)
        p = put_u64(p, dentry->creation_time);
        p = put_u64(p, dentry->last_access_time);
        p = put_u64(p, dentry->last_write_time);
-       if (!is_empty_file_hash(dentry->hash))
-               memcpy(p, dentry->hash, WIM_HASH_SIZE);
-       else
-               DEBUG("zero hash for %s\n", dentry->file_name_utf8);
+       memcpy(p, dentry->hash, WIM_HASH_SIZE);
        p += WIM_HASH_SIZE;
        p = put_u32(p, dentry->reparse_tag);
        p = put_u64(p, dentry->hard_link);
@@ -983,7 +1076,7 @@ int read_dentry_tree(const u8 metadata_resource[], u64 metadata_resource_len,
                }
 
                /* Advance to the offset of the next child. */
-               cur_offset += child->length;
+               cur_offset += dentry_total_length(child);
        }
 
        /* Link last child to first one, and set parent's
index ac2eeaf..2f51ecd 100644 (file)
@@ -2,12 +2,49 @@
 #define _WIMLIB_DENTRY_H
 
 #include "util.h"
+#include "config.h"
 #include <string.h>
 
 /* Size of the struct dentry up to and including the file_name_len. */
-#define WIM_DENTRY_DISK_SIZE 102
+#define WIM_DENTRY_DISK_SIZE    102
 
-#define WIM_ADS_ENTRY_DISK_SIZE (2 * sizeof(u64) + WIM_HASH_SIZE + sizeof(u16))
+#define WIM_ADS_ENTRY_DISK_SIZE 38
+
+#ifndef WITH_NTFS_3G
+/* 
+ * Reparse tags documented at 
+ * http://msdn.microsoft.com/en-us/library/dd541667(v=prot.10).aspx
+ *
+ * IO_REPARSE_TAG_SYMLINK is the only one we really care about.
+ */
+#define IO_REPARSE_TAG_RESERVED_ZERO   0x00000000
+#define IO_REPARSE_TAG_RESERVED_ONE    0x00000001
+#define IO_REPARSE_TAG_MOUNT_POINT     0xA0000003
+#define IO_REPARSE_TAG_HSM             0xC0000004
+#define IO_REPARSE_TAG_HSM2            0x80000006
+#define IO_REPARSE_TAG_DRIVER_EXTENDER 0x80000005
+#define IO_REPARSE_TAG_SIS             0x80000007
+#define IO_REPARSE_TAG_DFS             0x8000000A
+#define IO_REPARSE_TAG_DFSR            0x80000012
+#define IO_REPARSE_TAG_FILTER_MANAGER  0x8000000B
+#define IO_REPARSE_TAG_SYMLINK         0xA000000C
+#endif /* !WITH_NTFS_3G */
+
+#define FILE_ATTRIBUTE_READONLY            0x00000001
+#define FILE_ATTRIBUTE_HIDDEN              0x00000002
+#define FILE_ATTRIBUTE_SYSTEM              0x00000004
+#define FILE_ATTRIBUTE_DIRECTORY           0x00000010
+#define FILE_ATTRIBUTE_ARCHIVE             0x00000020
+#define FILE_ATTRIBUTE_DEVICE              0x00000040
+#define FILE_ATTRIBUTE_NORMAL              0x00000080
+#define FILE_ATTRIBUTE_TEMPORARY           0x00000100
+#define FILE_ATTRIBUTE_SPARSE_FILE         0x00000200
+#define FILE_ATTRIBUTE_REPARSE_POINT       0x00000400
+#define FILE_ATTRIBUTE_COMPRESSED          0x00000800
+#define FILE_ATTRIBUTE_OFFLINE             0x00001000
+#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000
+#define FILE_ATTRIBUTE_ENCRYPTED           0x00004000
+#define FILE_ATTRIBUTE_VIRTUAL             0x00010000
 
 /* Alternate data stream entry */
 struct ads_entry {
@@ -68,8 +105,8 @@ struct dentry {
        u64 subdir_offset;
 
        /* Reserved for future disuse.  Currently ignoring these fields. */
-       //u64 unused1;
-       //u64 unused2;
+       u64 unused1;
+       u64 unused2;
 
        /* Timestamps for the entry.  The timestamps are the number of
         * 100-nanosecond intervals that have elapsed since 12:00 A.M., January
@@ -88,7 +125,9 @@ struct dentry {
 
        /* Although M$'s documentation does not tell you this, it seems that the
         * reparse_reserved field does not actually exist.  So the hard_link
-        * field directly follows the reparse_tag on disk. */
+        * field directly follows the reparse_tag on disk.  EXCEPT when the
+        * dentry is actually a reparse point... well, just take a look at the
+        * read_dentry() function. */
        //u32 reparse_reserved;
 
        /* If the reparse_reserved field existed, there would be a 4-byte gap
@@ -135,21 +174,7 @@ struct dentry {
        int refcnt;
 };
 
-#define WIM_FILE_ATTRIBUTE_READONLY            0x00000001
-#define WIM_FILE_ATTRIBUTE_HIDDEN              0x00000002
-#define WIM_FILE_ATTRIBUTE_SYSTEM              0x00000004
-#define WIM_FILE_ATTRIBUTE_DIRECTORY           0x00000010
-#define WIM_FILE_ATTRIBUTE_ARCHIVE             0x00000020
-#define WIM_FILE_ATTRIBUTE_DEVICE              0x00000040
-#define WIM_FILE_ATTRIBUTE_NORMAL              0x00000080
-#define WIM_FILE_ATTRIBUTE_TEMPORARY           0x00000100
-#define WIM_FILE_ATTRIBUTE_SPARSE_FILE         0x00000200
-#define WIM_FILE_ATTRIBUTE_REPARSE_POINT       0x00000400
-#define WIM_FILE_ATTRIBUTE_COMPRESSED          0x00000800
-#define WIM_FILE_ATTRIBUTE_OFFLINE             0x00001000
-#define WIM_FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000
-#define WIM_FILE_ATTRIBUTE_ENCRYPTED           0x00004000
-#define WIM_FILE_ATTRIBUTE_VIRTUAL             0x00010000
+extern u64 dentry_total_length(const struct dentry *dentry);
 
 extern void stbuf_to_dentry(const struct stat *stbuf, struct dentry *dentry);
 
@@ -235,7 +260,7 @@ static inline bool dentry_is_only_child(const struct dentry *dentry)
 
 static inline bool dentry_is_directory(const struct dentry *dentry)
 {
-       return (dentry->attributes & WIM_FILE_ATTRIBUTE_DIRECTORY) != 0;
+       return (dentry->attributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
 }
 
 static inline bool dentry_is_regular_file(const struct dentry *dentry)
index f3b8da0..80549a6 100644 (file)
@@ -37,6 +37,7 @@
 
 #ifdef WITH_NTFS_3G
 #include <ntfs-3g/volume.h>
+#include <ntfs-3g/security.h>
 #endif
 
 /* Sets and creates the directory to which files are to be extracted when
@@ -88,7 +89,8 @@ done:
  */
 static int extract_regular_file(WIMStruct *w, 
                                const struct dentry *dentry, 
-                               const char *output_path)
+                               const char *output_path,
+                               int extract_flags)
 {
        struct lookup_table_entry *lte;
        int ret;
@@ -100,12 +102,12 @@ static int extract_regular_file(WIMStruct *w,
        /* If we already extracted the same file or a hard link copy of it, we
         * may be able to simply create a link.  The exact action is specified
         * by the current @link_type. */
-       if ((w->extract_flags & (WIMLIB_EXTRACT_FLAG_SYMLINK | WIMLIB_EXTRACT_FLAG_HARDLINK)) &&
+       if ((extract_flags & (WIMLIB_EXTRACT_FLAG_SYMLINK | WIMLIB_EXTRACT_FLAG_HARDLINK)) &&
              lte && lte->out_refcnt != 0)
        {
                wimlib_assert(lte->file_on_disk);
 
-               if (w->extract_flags & WIMLIB_EXTRACT_FLAG_HARDLINK) {
+               if (extract_flags & WIMLIB_EXTRACT_FLAG_HARDLINK) {
                        if (link(lte->file_on_disk, output_path) != 0) {
                                ERROR_WITH_ERRNO("Failed to hard link "
                                                 "`%s' to `%s'",
@@ -222,6 +224,13 @@ static int extract_directory(struct dentry *dentry, const char *output_path)
        return 0;
 }
 
+struct extract_args {
+       WIMStruct *w;
+       int extract_flags;
+#ifdef WITH_NTFS_3G
+       struct SECURITY_API *scapi;
+#endif
+};
 
 /* 
  * Extracts a file or directory from the WIM archive.  For use in
@@ -232,11 +241,13 @@ static int extract_directory(struct dentry *dentry, const char *output_path)
  */
 static int extract_regular_file_or_directory(struct dentry *dentry, void *arg)
 {
-       WIMStruct *w = (WIMStruct*)arg;
+       struct extract_args *args = arg;
+       WIMStruct *w = args->w;
+       int extract_flags = args->extract_flags;
        size_t len = strlen(w->output_dir);
        char output_path[len + dentry->full_path_utf8_len + 1];
 
-       if (w->extract_flags & WIMLIB_EXTRACT_FLAG_VERBOSE)
+       if (extract_flags & WIMLIB_EXTRACT_FLAG_VERBOSE)
                puts(dentry->full_path_utf8);
 
        memcpy(output_path, w->output_dir, len);
@@ -244,7 +255,7 @@ static int extract_regular_file_or_directory(struct dentry *dentry, void *arg)
        output_path[len + dentry->full_path_utf8_len] = '\0';
 
        if (dentry_is_regular_file(dentry)) {
-               return extract_regular_file(w, dentry, output_path);
+               return extract_regular_file(w, dentry, output_path, extract_flags);
        } else {
                if (dentry_is_root(dentry)) /* Root doesn't need to be extracted. */
                        return 0;
@@ -253,7 +264,8 @@ static int extract_regular_file_or_directory(struct dentry *dentry, void *arg)
        }
 }
 
-static int extract_single_image(WIMStruct *w, int image)
+
+static int extract_single_image(WIMStruct *w, int image, int extract_flags)
 {
        DEBUG("Extracting image %d", image);
 
@@ -262,14 +274,22 @@ static int extract_single_image(WIMStruct *w, int image)
        if (ret != 0)
                return ret;
 
+       struct extract_args args = {
+               .w = w,
+               .extract_flags = extract_flags,
+       #ifdef WITH_NTFS_3G
+               .scapi = NULL
+       #endif
+       };
+
        return for_dentry_in_tree(wim_root_dentry(w),
-                                 extract_regular_file_or_directory, w);
+                                 extract_regular_file_or_directory, &args);
 }
 
 
 /* Extracts all images from the WIM to w->output_dir, with the images placed in
  * subdirectories named by their image names. */
-static int extract_all_images(WIMStruct *w)
+static int extract_all_images(WIMStruct *w, int extract_flags)
 {
        size_t image_name_max_len = max(xml_get_max_image_name_len(w), 20);
        size_t output_path_len = strlen(w->output_dir);
@@ -294,7 +314,7 @@ static int extract_all_images(WIMStruct *w)
                ret = set_output_dir(w, buf);
                if (ret != 0)
                        goto done;
-               ret = extract_single_image(w, image);
+               ret = extract_single_image(w, image, extract_flags);
                if (ret != 0)
                        goto done;
        }
@@ -344,13 +364,12 @@ WIMLIBAPI int wimlib_extract_image(WIMStruct *w, int image,
                return WIMLIB_ERR_UNSUPPORTED;
        #endif
        }
-       w->extract_flags = flags;
        if (image == WIM_ALL_IMAGES) {
                w->is_multi_image_extraction = true;
-               ret = extract_all_images(w);
+               ret = extract_all_images(w, flags);
        } else {
                w->is_multi_image_extraction = false;
-               ret = extract_single_image(w, image);
+               ret = extract_single_image(w, image, flags);
        }
        return ret;
 
index fde95d0..5694ec2 100644 (file)
@@ -478,7 +478,7 @@ WIMLIBAPI int wimlib_add_image(WIMStruct *w, const char *dir,
        if (ret != 0)
                goto out_free_dentry_tree;
 
-       root_dentry->attributes |= WIM_FILE_ATTRIBUTE_DIRECTORY;
+       root_dentry->attributes |= FILE_ATTRIBUTE_DIRECTORY;
 
        /* Construct the dentry tree from the outside filesystem. */
        if (stat(dir, &root_stat) != 0) {
index bf194da..c6ce558 100644 (file)
@@ -495,7 +495,7 @@ static int wimfs_mkdir(const char *path, mode_t mode)
                return -EEXIST;
 
        newdir = new_dentry(basename);
-       newdir->attributes |= WIM_FILE_ATTRIBUTE_DIRECTORY;
+       newdir->attributes |= FILE_ATTRIBUTE_DIRECTORY;
        link_dentry(newdir, parent);
        return 0;
 }