]> wimlib.net Git - wimlib/blobdiff - src/extract.c
Add support for extract list files
[wimlib] / src / extract.c
index a7e62697a696617fed01c4bdb3e2f242049346df..aba92865ba9c3f2bee00175b4a8ec2cf8eff26d6 100644 (file)
@@ -49,6 +49,7 @@
 #include "wimlib/error.h"
 #include "wimlib/lookup_table.h"
 #include "wimlib/metadata.h"
+#include "wimlib/pathlist.h"
 #include "wimlib/paths.h"
 #include "wimlib/reparse.h"
 #include "wimlib/resource.h"
@@ -57,6 +58,7 @@
 #  include "wimlib/win32.h" /* for realpath() equivalent */
 #endif
 #include "wimlib/xml.h"
+#include "wimlib/wildcard.h"
 #include "wimlib/wim.h"
 
 #include <errno.h>
@@ -140,7 +142,7 @@ ref_stream_to_extract(struct wim_lookup_table_entry *lte,
                ctx->num_streams_remaining++;
        }
 
-       if (ctx->extract_flags & WIMLIB_EXTRACT_FLAG_SEQUENTIAL) {
+       if (!(ctx->extract_flags & WIMLIB_EXTRACT_FLAG_FILE_ORDER)) {
                struct wim_dentry **lte_dentries;
 
                /* Append dentry to this stream's array of dentries referencing
@@ -534,10 +536,10 @@ error:
  * This function operates slightly differently depending on whether @lte_spec is
  * NULL or not.  When @lte_spec is NULL, the behavior is to extract the default
  * file contents (unnamed stream), and, if named data streams are supported in
- * the extract mode and volume, any named data streams.  When @lte_spec is NULL,
- * the behavior is to extract only all copies of the stream @lte_spec, and in
- * addition use @lte_spec to set the reparse data or create the symbolic link if
- * appropriate.
+ * the extract mode and volume, any named data streams.  When @lte_spec is not
+ * NULL, the behavior is to extract only all copies of the stream @lte_spec, and
+ * in addition use @lte_spec to set the reparse data or create the symbolic link
+ * if appropriate.
  *
  * @path
  *     Path to file to extract (as can be passed to apply_operations
@@ -1182,8 +1184,7 @@ dentry_extract_dir_skeleton(struct wim_dentry *dentry, void *_ctx)
        return 0;
 }
 
-/* Create a file or directory, then immediately extract all streams.  This
- * assumes that WIMLIB_EXTRACT_FLAG_SEQUENTIAL is not specified, since the WIM
+/* Create a file or directory, then immediately extract all streams.  The WIM
  * may not be read sequentially by this function.  */
 static int
 dentry_extract(struct wim_dentry *dentry, void *_ctx)
@@ -1375,7 +1376,7 @@ out_delete_tmpfile:
 static int
 extract_stream_list(struct apply_ctx *ctx)
 {
-       if (ctx->extract_flags & WIMLIB_EXTRACT_FLAG_SEQUENTIAL) {
+       if (!(ctx->extract_flags & WIMLIB_EXTRACT_FLAG_FILE_ORDER)) {
                /* Sequential extraction: read the streams in the order in which
                 * they appear in the WIM file.  */
                struct read_stream_list_callbacks cbs = {
@@ -1435,7 +1436,7 @@ read_pwm_stream_header(WIMStruct *pwm, struct wim_lookup_table_entry *lte,
                return 0;
        }
 
-       if (buf.stream_hdr.magic != PWM_STREAM_MAGIC) {
+       if (le64_to_cpu(buf.stream_hdr.magic) != PWM_STREAM_MAGIC) {
                ERROR("Data read on pipe is invalid (expected stream header).");
                return WIMLIB_ERR_INVALID_PIPABLE_WIM;
        }
@@ -1508,7 +1509,7 @@ extract_streams_from_pipe(struct apply_ctx *ctx)
                    && (needed_lte = lookup_resource(lookup_table, found_lte->hash))
                    && (needed_lte->out_refcnt))
                {
-                       char *tmpfile_name = NULL;
+                       tchar *tmpfile_name = NULL;
                        struct wim_lookup_table_entry *lte_override;
                        struct wim_lookup_table_entry tmpfile_lte;
 
@@ -2430,8 +2431,7 @@ extract_tree(WIMStruct *wim, const tchar *wim_source_path, const tchar *target,
        }
 
        /* Finally, the important part: extract the tree of files.  */
-       if (extract_flags & (WIMLIB_EXTRACT_FLAG_SEQUENTIAL |
-                            WIMLIB_EXTRACT_FLAG_FROM_PIPE)) {
+       if (!(extract_flags & WIMLIB_EXTRACT_FLAG_FILE_ORDER)) {
                /* Sequential extraction requested, so two passes are needed
                 * (one for directory structure, one for streams.)  */
                if (progress_func)
@@ -2509,7 +2509,7 @@ out_free_realtarget:
 out_teardown_stream_list:
        /* Free memory allocated as part of the mapping from each
         * wim_lookup_table_entry to the dentries that reference it.  */
-       if (ctx.extract_flags & WIMLIB_EXTRACT_FLAG_SEQUENTIAL)
+       if (!(ctx.extract_flags & WIMLIB_EXTRACT_FLAG_FILE_ORDER))
                list_for_each_entry(lte, &ctx.stream_list, extraction_list)
                        if (lte->out_refcnt > ARRAY_LEN(lte->inline_lte_dentries))
                                FREE(lte->lte_dentries);
@@ -2547,6 +2547,9 @@ check_extract_command(struct wimlib_extract_command *cmd, int wim_header_flags)
                                                 WIMLIB_EXTRACT_FLAG_HARDLINK))
                return WIMLIB_ERR_INVALID_PARAM;
 
+       if (extract_flags & WIMLIB_EXTRACT_FLAG_GLOB_PATHS)
+               return WIMLIB_ERR_INVALID_PARAM;
+
        if ((extract_flags &
             (WIMLIB_EXTRACT_FLAG_NO_ACLS |
              WIMLIB_EXTRACT_FLAG_STRICT_ACLS)) == (WIMLIB_EXTRACT_FLAG_NO_ACLS |
@@ -2586,9 +2589,8 @@ check_extract_command(struct wimlib_extract_command *cmd, int wim_header_flags)
         * corresponding file or symbolic link data.  This needs to be handled
         * better.  */
        if ((extract_flags & (WIMLIB_EXTRACT_FLAG_UNIX_DATA |
-                             WIMLIB_EXTRACT_FLAG_SEQUENTIAL))
-                                   == (WIMLIB_EXTRACT_FLAG_UNIX_DATA |
-                                       WIMLIB_EXTRACT_FLAG_SEQUENTIAL))
+                             WIMLIB_EXTRACT_FLAG_FILE_ORDER))
+                                   == WIMLIB_EXTRACT_FLAG_UNIX_DATA)
        {
                if (extract_flags & WIMLIB_EXTRACT_FLAG_FROM_PIPE) {
                        WARNING("Setting UNIX file/owner group may "
@@ -2596,7 +2598,7 @@ check_extract_command(struct wimlib_extract_command *cmd, int wim_header_flags)
                                "          symbolic links "
                                "when applying from a pipe.");
                } else {
-                       extract_flags &= ~WIMLIB_EXTRACT_FLAG_SEQUENTIAL;
+                       extract_flags |= WIMLIB_EXTRACT_FLAG_FILE_ORDER;
                        WARNING("Disabling sequential extraction for "
                                "UNIX data mode");
                }
@@ -2878,8 +2880,6 @@ wimlib_extract_image_from_pipe(int pipe_fd, const tchar *image_num_or_name,
        if (extract_flags & WIMLIB_EXTRACT_FLAG_TO_STDOUT)
                return WIMLIB_ERR_INVALID_PARAM;
 
-       extract_flags |= WIMLIB_EXTRACT_FLAG_SEQUENTIAL;
-
        /* Read the WIM header from the pipe and get a WIMStruct to represent
         * the pipable WIM.  Caveats:  Unlike getting a WIMStruct with
         * wimlib_open_wim(), getting a WIMStruct in this way will result in
@@ -3037,3 +3037,122 @@ wimlib_extract_image(WIMStruct *wim,
        return do_wimlib_extract_image(wim, image, target, extract_flags,
                                       progress_func);
 }
+
+/* API function documented in wimlib.h  */
+WIMLIBAPI int
+wimlib_extract_pathlist(WIMStruct *wim, int image,
+                       const tchar *target,
+                       const tchar *path_list_file,
+                       int extract_flags,
+                       wimlib_progress_func_t progress_func)
+{
+       int ret;
+       tchar **paths;
+       size_t num_paths;
+       void *mem;
+
+       ret = read_path_list_file(path_list_file, &paths, &num_paths, &mem);
+       if (ret)
+               return ret;
+
+       ret = wimlib_extract_paths(wim, image, target,
+                                  (const tchar * const *)paths, num_paths,
+                                  extract_flags, progress_func);
+       FREE(paths);
+       FREE(mem);
+       return ret;
+}
+
+/* API function documented in wimlib.h  */
+WIMLIBAPI int
+wimlib_extract_paths(WIMStruct *wim,
+                    int image,
+                    const tchar *target,
+                    const tchar * const *paths,
+                    size_t num_paths,
+                    int extract_flags,
+                    wimlib_progress_func_t progress_func)
+{
+       int ret;
+       tchar **expanded_paths;
+       size_t num_expanded_paths;
+       struct wimlib_extract_command *cmds;
+
+       ret = select_wim_image(wim, image);
+       if (ret)
+               return ret;
+
+       if (extract_flags & WIMLIB_EXTRACT_FLAG_GLOB_PATHS) {
+               int 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 (extract_flags & WIMLIB_EXTRACT_FLAG_CASE_INSENSITIVE_GLOB)
+                       wildcard_flags |= WILDCARD_FLAG_CASE_INSENSITIVE;
+
+               ret = expand_wildcard_wim_paths(wim, paths, num_paths,
+                                               &expanded_paths,
+                                               &num_expanded_paths,
+                                               wildcard_flags);
+               if (ret)
+                       return ret;
+       } else {
+               expanded_paths = (tchar**)paths;
+               num_expanded_paths = num_paths;
+       }
+
+       cmds = CALLOC(num_expanded_paths, sizeof(cmds[0]));
+       if (cmds == NULL) {
+               ret = WIMLIB_ERR_NOMEM;
+               goto out_free_expanded_paths;
+       }
+
+       for (size_t i = 0; i < num_expanded_paths; i++) {
+               cmds[i].wim_source_path = expanded_paths[i];
+               cmds[i].extract_flags = 0;
+
+               tchar *dest_path;
+               size_t dest_len = 0;
+               dest_len += tstrlen(target);
+               dest_len += 1;
+               dest_len += tstrlen(expanded_paths[i]);
+               dest_len += 1;
+
+               dest_path = MALLOC(dest_len * sizeof(tchar));
+               if (dest_path == NULL) {
+                       ret = WIMLIB_ERR_NOMEM;
+                       goto out_free_extraction_cmds;
+               }
+               tchar *p = dest_path;
+               p = tmempcpy(p, target, tstrlen(target));
+               *p++ = OS_PREFERRED_PATH_SEPARATOR;
+               for (tchar *path_p = expanded_paths[i]; *path_p != '\0'; path_p++) {
+                       if (is_any_path_separator(*path_p))
+                               *p++ = OS_PREFERRED_PATH_SEPARATOR;
+                       else
+                               *p++ = *path_p;
+               }
+               *p++ = T('\0');
+               wimlib_assert(p - dest_path == dest_len);
+               cmds[i].fs_dest_path = dest_path;
+       }
+
+       ret = wimlib_extract_files(wim, image,
+                                  cmds, num_expanded_paths,
+                                  extract_flags & ~WIMLIB_EXTRACT_FLAG_GLOB_PATHS,
+                                  progress_func);
+out_free_extraction_cmds:
+       for (size_t i = 0; i < num_expanded_paths; i++)
+               FREE(cmds[i].fs_dest_path);
+       FREE(cmds);
+out_free_expanded_paths:
+       if (extract_flags & WIMLIB_EXTRACT_FLAG_GLOB_PATHS) {
+               for (size_t i = 0; i < num_expanded_paths; i++)
+                       FREE(expanded_paths[i]);
+               FREE(expanded_paths);
+       }
+       return ret;
+}