]> wimlib.net Git - wimlib/blobdiff - src/extract.c
s/NTFS-3g/NTFS-3G/g
[wimlib] / src / extract.c
index 0401758b79413344ebc05f68cf2e920a18892cdc..769abbe15235551b9d93a4f5647d0b66b133024d 100644 (file)
@@ -6,7 +6,7 @@
  */
 
 /*
- * Copyright (C) 2012, 2013, 2014, 2015 Eric Biggers
+ * Copyright (C) 2012-2016 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
@@ -28,7 +28,7 @@
  * wimlib_extract_pathlist().  Internally, all end up calling
  * do_wimlib_extract_paths() and extract_trees().
  *
- * Although wimlib supports multiple extraction modes/backends (NTFS-3g, UNIX,
+ * Although wimlib supports multiple extraction modes/backends (NTFS-3G, UNIX,
  * Win32), this file does not itself have code to extract files or directories
  * to any specific target; instead, it handles generic functionality and relies
  * on lower-level callback functions declared in `struct apply_operations' to do
@@ -41,6 +41,7 @@
 
 #include <errno.h>
 #include <fcntl.h>
+#include <stdlib.h>
 #include <sys/stat.h>
 #include <unistd.h>
 
 #include "wimlib/endianness.h"
 #include "wimlib/error.h"
 #include "wimlib/metadata.h"
+#include "wimlib/object_id.h"
 #include "wimlib/pathlist.h"
 #include "wimlib/paths.h"
+#include "wimlib/pattern.h"
 #include "wimlib/reparse.h"
 #include "wimlib/resource.h"
 #include "wimlib/security.h"
 #include "wimlib/unix_data.h"
-#include "wimlib/wildcard.h"
 #include "wimlib/wim.h"
 #include "wimlib/win32.h" /* for realpath() equivalent */
 #include "wimlib/xml.h"
         WIMLIB_EXTRACT_FLAG_STRICT_GLOB                |       \
         WIMLIB_EXTRACT_FLAG_NO_ATTRIBUTES              |       \
         WIMLIB_EXTRACT_FLAG_NO_PRESERVE_DIR_STRUCTURE  |       \
-        WIMLIB_EXTRACT_FLAG_WIMBOOT)
+        WIMLIB_EXTRACT_FLAG_WIMBOOT                    |       \
+        WIMLIB_EXTRACT_FLAG_COMPACT_XPRESS4K           |       \
+        WIMLIB_EXTRACT_FLAG_COMPACT_XPRESS8K           |       \
+        WIMLIB_EXTRACT_FLAG_COMPACT_XPRESS16K          |       \
+        WIMLIB_EXTRACT_FLAG_COMPACT_LZX                        \
+        )
 
 /* Send WIMLIB_PROGRESS_MSG_EXTRACT_FILE_STRUCTURE or
  * WIMLIB_PROGRESS_MSG_EXTRACT_METADATA.  */
@@ -254,6 +261,55 @@ read_blobs_from_pipe(struct apply_ctx *ctx, const struct read_blob_callbacks *cb
        return 0;
 }
 
+static int
+handle_pwm_metadata_resource(WIMStruct *pwm, int image, bool is_needed)
+{
+       struct blob_descriptor *blob;
+       struct wim_reshdr reshdr;
+       struct wim_resource_descriptor *rdesc;
+       int ret;
+
+       ret = WIMLIB_ERR_NOMEM;
+       blob = new_blob_descriptor();
+       if (!blob)
+               goto out;
+
+       ret = read_pwm_blob_header(pwm, blob->hash, &reshdr, NULL);
+       if (ret)
+               goto out;
+
+       ret = WIMLIB_ERR_INVALID_PIPABLE_WIM;
+       if (!(reshdr.flags & WIM_RESHDR_FLAG_METADATA)) {
+               ERROR("Expected metadata resource, but found non-metadata "
+                     "resource");
+               goto out;
+       }
+
+       ret = WIMLIB_ERR_NOMEM;
+       rdesc = MALLOC(sizeof(*rdesc));
+       if (!rdesc)
+               goto out;
+
+       wim_reshdr_to_desc_and_blob(&reshdr, pwm, rdesc, blob);
+       pwm->refcnt++;
+
+       ret = WIMLIB_ERR_NOMEM;
+       pwm->image_metadata[image - 1] = new_unloaded_image_metadata(blob);
+       if (!pwm->image_metadata[image - 1])
+               goto out;
+       blob = NULL;
+
+       /* If the metadata resource is for the image being extracted, then parse
+        * it and save the metadata in memory.  Otherwise, skip over it.  */
+       if (is_needed)
+               ret = select_wim_image(pwm, image);
+       else
+               ret = skip_wim_resource(rdesc);
+out:
+       free_blob_descriptor(blob);
+       return ret;
+}
+
 /* Creates a temporary file opened for writing.  The open file descriptor is
  * returned in @fd_ret and its name is returned in @name_ret (dynamically
  * allocated).  */
@@ -261,27 +317,33 @@ static int
 create_temporary_file(struct filedes *fd_ret, tchar **name_ret)
 {
        tchar *name;
-       int open_flags;
        int raw_fd;
 
+#ifdef __WIN32__
 retry:
-       name = ttempnam(NULL, T("wimlib"));
+       name = _wtempnam(NULL, L"wimlib");
        if (!name) {
                ERROR_WITH_ERRNO("Failed to create temporary filename");
                return WIMLIB_ERR_NOMEM;
        }
-
-       open_flags = O_WRONLY | O_CREAT | O_EXCL | O_BINARY;
-#ifdef __WIN32__
-       open_flags |= _O_SHORT_LIVED;
-#endif
-       raw_fd = topen(name, open_flags, 0600);
+       raw_fd = _wopen(name, O_WRONLY | O_CREAT | O_EXCL | O_BINARY |
+                       _O_SHORT_LIVED, 0600);
+       if (raw_fd < 0 && errno == EEXIST) {
+               FREE(name);
+               goto retry;
+       }
+#else /* __WIN32__ */
+       const char *tmpdir = getenv("TMPDIR");
+       if (!tmpdir)
+               tmpdir = P_tmpdir;
+       name = MALLOC(strlen(tmpdir) + 1 + 6 + 6 + 1);
+       if (!name)
+               return WIMLIB_ERR_NOMEM;
+       sprintf(name, "%s/wimlibXXXXXX", tmpdir);
+       raw_fd = mkstemp(name);
+#endif /* !__WIN32__ */
 
        if (raw_fd < 0) {
-               if (errno == EEXIST) {
-                       FREE(name);
-                       goto retry;
-               }
                ERROR_WITH_ERRNO("Failed to create temporary file "
                                 "\"%"TS"\"", name);
                FREE(name);
@@ -341,30 +403,9 @@ extract_chunk_wrapper(const void *chunk, size_t size, void *_ctx)
                if (ret)
                        return ret;
 
-               if (progress->extract.completed_bytes >=
-                   progress->extract.total_bytes)
-               {
-                       ctx->next_progress = UINT64_MAX;
-               } else {
-                       /* Send new message as soon as another 1/128 of the
-                        * total has been extracted.  (Arbitrary number.)  */
-                       ctx->next_progress =
-                               progress->extract.completed_bytes +
-                                       progress->extract.total_bytes / 128;
-
-                       /* ... Unless that would be more than 5000000 bytes, in
-                        * which case send the next after the next 5000000
-                        * bytes.  (Another arbitrary number.)  */
-                       if (progress->extract.completed_bytes + 5000000 <
-                           ctx->next_progress)
-                               ctx->next_progress =
-                                       progress->extract.completed_bytes + 5000000;
-
-                       /* ... But always send a message as soon as we're
-                        * completely done.  */
-                       if (progress->extract.total_bytes < ctx->next_progress)
-                               ctx->next_progress = progress->extract.total_bytes;
-               }
+               set_next_progress(progress->extract.completed_bytes,
+                                 progress->extract.total_bytes,
+                                 &ctx->next_progress);
        }
 
        if (unlikely(filedes_valid(&ctx->tmpfile_fd))) {
@@ -522,14 +563,14 @@ remove_duplicate_trees(struct wim_dentry **trees, size_t num_trees)
 {
        size_t i, j = 0;
        for (i = 0; i < num_trees; i++) {
-               if (!trees[i]->tmp_flag) {
+               if (!trees[i]->d_tmp_flag) {
                        /* Found distinct dentry.  */
-                       trees[i]->tmp_flag = 1;
+                       trees[i]->d_tmp_flag = 1;
                        trees[j++] = trees[i];
                }
        }
        for (i = 0; i < j; i++)
-               trees[i]->tmp_flag = 0;
+               trees[i]->d_tmp_flag = 0;
        return j;
 }
 
@@ -543,23 +584,23 @@ remove_contained_trees(struct wim_dentry **trees, size_t num_trees)
 {
        size_t i, j = 0;
        for (i = 0; i < num_trees; i++)
-               trees[i]->tmp_flag = 1;
+               trees[i]->d_tmp_flag = 1;
        for (i = 0; i < num_trees; i++) {
                struct wim_dentry *d = trees[i];
                while (!dentry_is_root(d)) {
                        d = d->d_parent;
-                       if (d->tmp_flag)
+                       if (d->d_tmp_flag)
                                goto tree_contained;
                }
                trees[j++] = trees[i];
                continue;
 
        tree_contained:
-               trees[i]->tmp_flag = 0;
+               trees[i]->d_tmp_flag = 0;
        }
 
        for (i = 0; i < j; i++)
-               trees[i]->tmp_flag = 0;
+               trees[i]->d_tmp_flag = 0;
        return j;
 }
 
@@ -580,8 +621,10 @@ dentry_reset_extraction_list_node(struct wim_dentry *dentry)
 static int
 dentry_delete_from_list(struct wim_dentry *dentry, void *_ignore)
 {
-       list_del(&dentry->d_extraction_list_node);
-       dentry_reset_extraction_list_node(dentry);
+       if (will_extract_dentry(dentry)) {
+               list_del(&dentry->d_extraction_list_node);
+               dentry_reset_extraction_list_node(dentry);
+       }
        return 0;
 }
 
@@ -674,19 +717,20 @@ file_name_valid(utf16lechar *name, size_t num_chars, bool fix)
        if (num_chars == 0)
                return true;
        for (i = 0; i < num_chars; i++) {
-               switch (name[i]) {
+               switch (le16_to_cpu(name[i])) {
        #ifdef __WIN32__
-               case cpu_to_le16('\\'):
-               case cpu_to_le16(':'):
-               case cpu_to_le16('*'):
-               case cpu_to_le16('?'):
-               case cpu_to_le16('"'):
-               case cpu_to_le16('<'):
-               case cpu_to_le16('>'):
-               case cpu_to_le16('|'):
+               case '\x01'...'\x1F':
+               case '\\':
+               case ':':
+               case '*':
+               case '?':
+               case '"':
+               case '<':
+               case '>':
+               case '|':
        #endif
-               case cpu_to_le16('/'):
-               case cpu_to_le16('\0'):
+               case '/':
+               case '\0':
                        if (fix)
                                name[i] = replacement_char;
                        else
@@ -694,16 +738,6 @@ file_name_valid(utf16lechar *name, size_t num_chars, bool fix)
                }
        }
 
-#ifdef __WIN32__
-       if (name[num_chars - 1] == cpu_to_le16(' ') ||
-           name[num_chars - 1] == cpu_to_le16('.'))
-       {
-               if (fix)
-                       name[num_chars - 1] = replacement_char;
-               else
-                       return false;
-       }
-#endif
        return true;
 }
 
@@ -753,11 +787,12 @@ dentry_calculate_extraction_name(struct wim_dentry *dentry,
        }
 
        if (file_name_valid(dentry->d_name, dentry->d_name_nbytes / 2, false)) {
+               size_t nbytes = 0;
                ret = utf16le_get_tstr(dentry->d_name,
                                       dentry->d_name_nbytes,
                                       (const tchar **)&dentry->d_extraction_name,
-                                      &dentry->d_extraction_name_nchars);
-               dentry->d_extraction_name_nchars /= sizeof(tchar);
+                                      &nbytes);
+               dentry->d_extraction_name_nchars = nbytes / sizeof(tchar);
                return ret;
        } else {
                if (ctx->extract_flags & WIMLIB_EXTRACT_FLAG_REPLACE_INVALID_FILENAMES)
@@ -1000,10 +1035,11 @@ ref_stream_if_needed(struct wim_dentry *dentry, struct wim_inode *inode,
                         * - file is a directory
                         * - file is encrypted
                         * - backend needs to create the file as UNIX symlink
-                        * - backend will extract the stream as externally backed
+                        * - backend will extract the stream as externally
+                        *   backed from the WIM archive itself
                         */
-                       if (ctx->apply_ops->will_externally_back) {
-                               int ret = (*ctx->apply_ops->will_externally_back)(dentry, ctx);
+                       if (ctx->apply_ops->will_back_from_wim) {
+                               int ret = (*ctx->apply_ops->will_back_from_wim)(dentry, ctx);
                                if (ret > 0) /* Error?  */
                                        return ret;
                                if (ret < 0) /* Won't externally back?  */
@@ -1094,12 +1130,14 @@ static void
 inode_tally_features(const struct wim_inode *inode,
                     struct wim_features *features)
 {
-       if (inode->i_attributes & FILE_ATTRIBUTE_ARCHIVE)
-               features->archive_files++;
+       if (inode->i_attributes & FILE_ATTRIBUTE_READONLY)
+               features->readonly_files++;
        if (inode->i_attributes & FILE_ATTRIBUTE_HIDDEN)
                features->hidden_files++;
        if (inode->i_attributes & FILE_ATTRIBUTE_SYSTEM)
                features->system_files++;
+       if (inode->i_attributes & FILE_ATTRIBUTE_ARCHIVE)
+               features->archive_files++;
        if (inode->i_attributes & FILE_ATTRIBUTE_COMPRESSED)
                features->compressed_files++;
        if (inode->i_attributes & FILE_ATTRIBUTE_ENCRYPTED) {
@@ -1125,6 +1163,8 @@ inode_tally_features(const struct wim_inode *inode,
                features->security_descriptors++;
        if (inode_has_unix_data(inode))
                features->unix_data++;
+       if (inode_has_object_id(inode))
+               features->object_ids++;
 }
 
 /* Tally features necessary to extract a dentry and the corresponding inode.  */
@@ -1177,9 +1217,11 @@ do_feature_check(const struct wim_features *required_features,
 
        /* File attributes.  */
        if (!(extract_flags & WIMLIB_EXTRACT_FLAG_NO_ATTRIBUTES)) {
-               /* Note: Don't bother the user about FILE_ATTRIBUTE_ARCHIVE.
-                * We're an archive program, so theoretically we can do what we
-                * want with it.  */
+
+               if (required_features->readonly_files &&
+                   !supported_features->readonly_files)
+                       WARNING("Ignoring FILE_ATTRIBUTE_READONLY of %lu files",
+                               required_features->readonly_files);
 
                if (required_features->hidden_files &&
                    !supported_features->hidden_files)
@@ -1191,6 +1233,10 @@ do_feature_check(const struct wim_features *required_features,
                        WARNING("Ignoring FILE_ATTRIBUTE_SYSTEM of %lu files",
                                required_features->system_files);
 
+               /* Note: Don't bother the user about FILE_ATTRIBUTE_ARCHIVE.
+                * We're an archive program, so theoretically we can do what we
+                * want with it.  */
+
                if (required_features->compressed_files &&
                    !supported_features->compressed_files)
                        WARNING("Ignoring FILE_ATTRIBUTE_COMPRESSED of %lu files",
@@ -1271,6 +1317,12 @@ do_feature_check(const struct wim_features *required_features,
                        required_features->unix_data);
        }
 
+       /* Object IDs.  */
+       if (required_features->object_ids && !supported_features->object_ids) {
+               WARNING("Ignoring object IDs of %lu files",
+                       required_features->object_ids);
+       }
+
        /* DOS Names.  */
        if (required_features->short_names &&
            !supported_features->short_names)
@@ -1407,12 +1459,12 @@ extract_trees(WIMStruct *wim, struct wim_dentry **trees, size_t num_trees,
                 * subtract <HARDLINKBYTES> from this if hard links are
                 * supported by the extraction mode.)  */
                ctx->progress.extract.total_bytes =
-                       wim_info_get_image_total_bytes(wim->wim_info,
-                                                      wim->current_image);
+                       xml_get_image_total_bytes(wim->xml_info,
+                                                 wim->current_image);
                if (ctx->supported_features.hard_links) {
                        ctx->progress.extract.total_bytes -=
-                               wim_info_get_image_hard_link_bytes(wim->wim_info,
-                                                                  wim->current_image);
+                               xml_get_image_hard_link_bytes(wim->xml_info,
+                                                             wim->current_image);
                }
        }
 
@@ -1490,7 +1542,7 @@ check_extract_flags(const WIMStruct *wim, int *extract_flags_p)
 
 #ifndef WITH_NTFS_3G
        if (extract_flags & WIMLIB_EXTRACT_FLAG_NTFS) {
-               ERROR("wimlib was compiled without support for NTFS-3g, so\n"
+               ERROR("wimlib was compiled without support for NTFS-3G, so\n"
                      "        it cannot apply a WIM image directly to an NTFS volume.");
                return WIMLIB_ERR_UNSUPPORTED;
        }
@@ -1506,6 +1558,34 @@ check_extract_flags(const WIMStruct *wim, int *extract_flags_p)
 #endif
        }
 
+       if (extract_flags & (WIMLIB_EXTRACT_FLAG_COMPACT_XPRESS4K |
+                            WIMLIB_EXTRACT_FLAG_COMPACT_XPRESS8K |
+                            WIMLIB_EXTRACT_FLAG_COMPACT_XPRESS16K |
+                            WIMLIB_EXTRACT_FLAG_COMPACT_LZX))
+       {
+       #ifdef __WIN32__
+               int count = 0;
+               count += ((extract_flags & WIMLIB_EXTRACT_FLAG_COMPACT_XPRESS4K) != 0);
+               count += ((extract_flags & WIMLIB_EXTRACT_FLAG_COMPACT_XPRESS8K) != 0);
+               count += ((extract_flags & WIMLIB_EXTRACT_FLAG_COMPACT_XPRESS16K) != 0);
+               count += ((extract_flags & WIMLIB_EXTRACT_FLAG_COMPACT_LZX) != 0);
+               if (count != 1) {
+                       ERROR("Only one compression format can be specified "
+                             "for compact-mode extraction!");
+                       return WIMLIB_ERR_INVALID_PARAM;
+               }
+               if (extract_flags & WIMLIB_EXTRACT_FLAG_WIMBOOT) {
+                       ERROR("Compact-mode extraction and WIMBoot-mode "
+                             "extraction are mutually exclusive!");
+                       return WIMLIB_ERR_INVALID_PARAM;
+               }
+       #else
+               ERROR("Compact-mode extraction (System Compression) "
+                     "is only supported on Windows!");
+               return WIMLIB_ERR_UNSUPPORTED;
+       #endif
+       }
+
 
        if ((extract_flags & (WIMLIB_EXTRACT_FLAG_RPFIX |
                              WIMLIB_EXTRACT_FLAG_NORPFIX |
@@ -1522,22 +1602,6 @@ check_extract_flags(const WIMStruct *wim, int *extract_flags_p)
        return 0;
 }
 
-static u32
-get_wildcard_flags(int extract_flags)
-{
-       u32 wildcard_flags = 0;
-
-       if (extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_GLOB)
-               wildcard_flags |= WILDCARD_FLAG_ERROR_IF_NO_MATCH;
-       else
-               wildcard_flags |= WILDCARD_FLAG_WARN_IF_NO_MATCH;
-
-       if (default_ignore_case)
-               wildcard_flags |= WILDCARD_FLAG_CASE_INSENSITIVE;
-
-       return wildcard_flags;
-}
-
 struct append_dentry_ctx {
        struct wim_dentry **dentries;
        size_t num_dentries;
@@ -1566,6 +1630,31 @@ append_dentry_cb(struct wim_dentry *dentry, void *_ctx)
        return 0;
 }
 
+/* Append dentries matched by a path which can contain wildcard characters.  */
+static int
+append_matched_dentries(WIMStruct *wim, const tchar *orig_pattern,
+                       int extract_flags, struct append_dentry_ctx *ctx)
+{
+       const size_t count_before = ctx->num_dentries;
+       tchar *pattern;
+       int ret;
+
+       pattern = canonicalize_wim_path(orig_pattern);
+       if (!pattern)
+               return WIMLIB_ERR_NOMEM;
+       ret = expand_path_pattern(wim_get_current_root_dentry(wim), pattern,
+                                 append_dentry_cb, ctx);
+       FREE(pattern);
+       if (ret || ctx->num_dentries > count_before)
+               return ret;
+       if (extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_GLOB) {
+               ERROR("No matches for path pattern \"%"TS"\"", orig_pattern);
+               return WIMLIB_ERR_PATH_DOES_NOT_EXIST;
+       }
+       WARNING("No matches for path pattern \"%"TS"\"", orig_pattern);
+       return 0;
+}
+
 static int
 do_wimlib_extract_paths(WIMStruct *wim, int image, const tchar *target,
                        const tchar * const *paths, size_t num_paths,
@@ -1608,20 +1697,10 @@ do_wimlib_extract_paths(WIMStruct *wim, int image, const tchar *target,
                        .num_alloc_dentries = 0,
                };
 
-               u32 wildcard_flags = get_wildcard_flags(extract_flags);
-
                for (size_t i = 0; i < num_paths; i++) {
-                       tchar *path = canonicalize_wim_path(paths[i]);
-                       if (path == NULL) {
-                               ret = WIMLIB_ERR_NOMEM;
-                               trees = append_dentry_ctx.dentries;
-                               goto out_free_trees;
-                       }
-                       ret = expand_wildcard(wim, path,
-                                             append_dentry_cb,
-                                             &append_dentry_ctx,
-                                             wildcard_flags);
-                       FREE(path);
+                       ret = append_matched_dentries(wim, paths[i],
+                                                     extract_flags,
+                                                     &append_dentry_ctx);
                        if (ret) {
                                trees = append_dentry_ctx.dentries;
                                goto out_free_trees;
@@ -1693,7 +1772,8 @@ image_name_ok_as_dir(const tchar *image_name)
        return image_name && *image_name &&
                !tstrpbrk(image_name, filename_forbidden_chars) &&
                tstrcmp(image_name, T(".")) &&
-               tstrcmp(image_name, T(".."));
+               tstrcmp(image_name, T("..")) &&
+               tstrlen(image_name) <= 128;
 }
 
 /* Extracts all images from the WIM to the directory @target, with the images
@@ -1701,9 +1781,8 @@ image_name_ok_as_dir(const tchar *image_name)
 static int
 extract_all_images(WIMStruct *wim, const tchar *target, int extract_flags)
 {
-       size_t image_name_max_len = max(xml_get_max_image_name_len(wim), 20);
        size_t output_path_len = tstrlen(target);
-       tchar buf[output_path_len + 1 + image_name_max_len + 1];
+       tchar buf[output_path_len + 1 + 128 + 1];
        int ret;
        int image;
        const tchar *image_name;
@@ -1859,7 +1938,7 @@ wimlib_extract_image_from_pipe_with_progress(int pipe_fd,
                if (ret)
                        goto out_wimlib_free;
 
-               if (wim_info_get_num_images(pwm->wim_info) != pwm->hdr.image_count) {
+               if (xml_get_image_count(pwm->xml_info) != pwm->hdr.image_count) {
                        ERROR("Image count in XML data is not the same as in WIM header.");
                        ret = WIMLIB_ERR_IMAGE_COUNT;
                        goto out_wimlib_free;
@@ -1892,52 +1971,9 @@ wimlib_extract_image_from_pipe_with_progress(int pipe_fd,
 
        /* Load the needed metadata resource.  */
        for (i = 1; i <= pwm->hdr.image_count; i++) {
-               struct wim_image_metadata *imd;
-               struct wim_reshdr reshdr;
-               struct wim_resource_descriptor *metadata_rdesc;
-
-               imd = pwm->image_metadata[i - 1];
-
-               ret = WIMLIB_ERR_NOMEM;
-               imd->metadata_blob = new_blob_descriptor();
-               if (!imd->metadata_blob)
-                       goto out_wimlib_free;
-
-               imd->metadata_blob->is_metadata = 1;
-
-               ret = read_pwm_blob_header(pwm, imd->metadata_blob->hash,
-                                          &reshdr, NULL);
+               ret = handle_pwm_metadata_resource(pwm, i, i == image);
                if (ret)
                        goto out_wimlib_free;
-
-               if (!(reshdr.flags & WIM_RESHDR_FLAG_METADATA)) {
-                       ERROR("Expected metadata resource, but found "
-                             "non-metadata resource");
-                       ret = WIMLIB_ERR_INVALID_PIPABLE_WIM;
-                       goto out_wimlib_free;
-               }
-
-               ret = WIMLIB_ERR_NOMEM;
-               metadata_rdesc = MALLOC(sizeof(struct wim_resource_descriptor));
-               if (!metadata_rdesc)
-                       goto out_wimlib_free;
-               wim_reshdr_to_desc_and_blob(&reshdr, pwm, metadata_rdesc,
-                                           imd->metadata_blob);
-
-               if (i == image) {
-                       /* Metadata resource is for the image being extracted.
-                        * Parse it and save the metadata in memory.  */
-                       ret = read_metadata_resource(imd);
-                       if (ret)
-                               goto out_wimlib_free;
-                       imd->modified = 1;
-               } else {
-                       /* Metadata resource is not for the image being
-                        * extracted.  Skip over it.  */
-                       ret = skip_wim_resource(metadata_rdesc);
-                       if (ret)
-                               goto out_wimlib_free;
-               }
        }
        /* Extract the image.  */
        extract_flags |= WIMLIB_EXTRACT_FLAG_FROM_PIPE;