]> wimlib.net Git - wimlib/blobdiff - src/extract.c
Don't create unnecessary temporary files
[wimlib] / src / extract.c
index 9cbac117f54438d25372c90cb43dd4df4c327bb5..bc769eec798d284f61ddee9f28fd006304b616bd 100644 (file)
@@ -6,7 +6,7 @@
  */
 
 /*
- * Copyright (C) 2012, 2013 Eric Biggers
+ * Copyright (C) 2012, 2013, 2014 Eric Biggers
  *
  * This file is part of wimlib, a library for working with WIM files.
  *
@@ -26,9 +26,9 @@
 
 /*
  * This file provides the API functions wimlib_extract_image(),
- * wimlib_extract_image_from_pipe(), wimlib_extract_files(),
- * wimlib_extract_paths(), and wimlib_extract_pathlist().  Internally, all end
- * up calling do_wimlib_extract_paths() and extract_trees().
+ * wimlib_extract_image_from_pipe(), wimlib_extract_paths(), and
+ * 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,
  * Win32), this file does not itself have code to extract files or directories
@@ -68,8 +68,7 @@
 
 #define WIMLIB_EXTRACT_FLAG_MULTI_IMAGE 0x80000000
 #define WIMLIB_EXTRACT_FLAG_FROM_PIPE   0x40000000
-#define WIMLIB_EXTRACT_FLAG_FILEMODE    0x20000000
-#define WIMLIB_EXTRACT_FLAG_IMAGEMODE   0x10000000
+#define WIMLIB_EXTRACT_FLAG_IMAGEMODE   0x20000000
 
 /* Keep in sync with wimlib.h  */
 #define WIMLIB_EXTRACT_MASK_PUBLIC                             \
@@ -94,7 +93,8 @@
         WIMLIB_EXTRACT_FLAG_GLOB_PATHS                 |       \
         WIMLIB_EXTRACT_FLAG_STRICT_GLOB                |       \
         WIMLIB_EXTRACT_FLAG_NO_ATTRIBUTES              |       \
-        WIMLIB_EXTRACT_FLAG_NO_PRESERVE_DIR_STRUCTURE)
+        WIMLIB_EXTRACT_FLAG_NO_PRESERVE_DIR_STRUCTURE  |       \
+        WIMLIB_EXTRACT_FLAG_WIMBOOT)
 
 static bool
 dentry_in_list(const struct wim_dentry *dentry)
@@ -494,7 +494,8 @@ extract_streams(const tchar *path, struct apply_ctx *ctx,
                                }
                        } else {
                                ret = ctx->ops->extract_unnamed_stream(
-                                                       file_spec, lte, ctx);
+                                                       file_spec, lte, ctx,
+                                                       dentry);
                                if (ret)
                                        goto error;
                        }
@@ -1170,6 +1171,7 @@ create_temporary_file(struct filedes *fd_ret, tchar **name_ret)
 {
        tchar *name;
        int raw_fd;
+       int open_flags;
 
 retry:
        name = ttempnam(NULL, T("wimlib"));
@@ -1178,7 +1180,11 @@ retry:
                return WIMLIB_ERR_NOMEM;
        }
 
-       raw_fd = topen(name, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0600);
+       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);
 
        if (raw_fd < 0) {
                if (errno == EEXIST) {
@@ -1267,14 +1273,23 @@ need_tmpfile_to_extract(struct wim_lookup_table_entry *lte,
 }
 
 static int
-begin_extract_stream_to_tmpfile(struct wim_lookup_table_entry *lte,
-                               bool is_partial_res,
-                               void *_ctx)
+begin_extract_stream(struct wim_lookup_table_entry *lte,
+                    u32 flags, void *_ctx)
 {
        struct apply_ctx *ctx = _ctx;
        int ret;
 
-       if (!need_tmpfile_to_extract(lte, is_partial_res)) {
+       if (flags & BEGIN_STREAM_FLAG_WHOLE_STREAM) {
+               DEBUG("Whole stream (size=%"PRIu64") will be read into memory",
+                     lte->size);
+               ctx->cur_stream = lte;
+               filedes_invalidate(&ctx->tmpfile_fd);
+               return 0;
+       }
+
+       if (!need_tmpfile_to_extract(lte,
+                                    (flags & BEGIN_STREAM_FLAG_PARTIAL_RESOURCE)))
+       {
                DEBUG("Temporary file not needed "
                      "for stream (size=%"PRIu64")", lte->size);
                ret = extract_stream_instances(lte, lte, ctx);
@@ -1289,14 +1304,42 @@ begin_extract_stream_to_tmpfile(struct wim_lookup_table_entry *lte,
 }
 
 static int
-end_extract_stream_to_tmpfile(struct wim_lookup_table_entry *lte,
-                             int status, void *_ctx)
+extract_chunk(const void *chunk, size_t size, void *_ctx)
+{
+       struct apply_ctx *ctx = _ctx;
+       int ret;
+
+       if (filedes_valid(&ctx->tmpfile_fd)) {
+               ret = full_write(&ctx->tmpfile_fd, chunk, size);
+               if (ret)
+                       ERROR_WITH_ERRNO("Error writing to file descriptor");
+       } else {
+               struct wim_lookup_table_entry lte_override;
+
+               memcpy(&lte_override, ctx->cur_stream,
+                      sizeof(struct wim_lookup_table_entry));
+
+               lte_override.resource_location = RESOURCE_IN_ATTACHED_BUFFER;
+               lte_override.size = size;
+               lte_override.attached_buffer = (void *)chunk;
+
+               ret = extract_stream_instances(ctx->cur_stream, &lte_override, ctx);
+       }
+       return ret;
+}
+
+static int
+end_extract_stream(struct wim_lookup_table_entry *lte,
+                  int status, void *_ctx)
 {
        struct apply_ctx *ctx = _ctx;
        struct wim_lookup_table_entry lte_override;
        int ret;
        int errno_save = errno;
 
+       if (!filedes_valid(&ctx->tmpfile_fd))
+               return status;
+
        ret = filedes_close(&ctx->tmpfile_fd);
 
        if (status) {
@@ -1336,11 +1379,11 @@ static int
 extract_stream_list(struct apply_ctx *ctx)
 {
        struct read_stream_list_callbacks cbs = {
-               .begin_stream           = begin_extract_stream_to_tmpfile,
+               .begin_stream           = begin_extract_stream,
                .begin_stream_ctx       = ctx,
-               .consume_chunk          = extract_chunk_to_fd,
-               .consume_chunk_ctx      = &ctx->tmpfile_fd,
-               .end_stream             = end_extract_stream_to_tmpfile,
+               .consume_chunk          = extract_chunk,
+               .consume_chunk_ctx      = ctx,
+               .end_stream             = end_extract_stream,
                .end_stream_ctx         = ctx,
        };
        return read_stream_list(&ctx->stream_list,
@@ -1789,8 +1832,8 @@ dentry_calculate_extraction_name(struct wim_dentry *dentry,
        if (!ctx->ops->supports_case_sensitive_filenames)
        {
                struct wim_dentry *other;
-               list_for_each_entry(other, &dentry->case_insensitive_conflict_list,
-                                   case_insensitive_conflict_list)
+               list_for_each_entry(other, &dentry->d_ci_conflict_list,
+                                   d_ci_conflict_list)
                {
                        if (dentry_in_list(other)) {
                                if (ctx->extract_flags &
@@ -2434,21 +2477,7 @@ extract_trees(WIMStruct *wim, struct wim_dentry **trees, size_t num_trees,
                ctx.progress.extract.target = target;
        }
 
-       if (extract_flags & WIMLIB_EXTRACT_FLAG_FILEMODE) {
-               /* Called from wimlib_extract_files().  There should be only 1
-                * tree, and directory structure should not be preserved.  */
-               wimlib_assert(num_trees == 1);
-               wimlib_assert(extract_flags &
-                             WIMLIB_EXTRACT_FLAG_NO_PRESERVE_DIR_STRUCTURE);
-               ret = calculate_dentry_full_path(trees[0]);
-               if (ret)
-                       return ret;
-               ctx.progress.extract.extract_root_wim_source_path = trees[0]->_full_path;
-               ctx.target_dentry = trees[0];
-       } else {
-               ctx.progress.extract.extract_root_wim_source_path = T("");
-               ctx.target_dentry = wim_root_dentry(wim);
-       }
+       ctx.target_dentry = wim_root_dentry(wim);
        /* Note: ctx.target_dentry represents the dentry that gets extracted to
         * @target.  There may be none, in which case it gets set to the image
         * root and never matches any of the dentries actually being extracted.
@@ -2542,6 +2571,18 @@ extract_trees(WIMStruct *wim, struct wim_dentry **trees, size_t num_trees,
                        goto out_destroy_stream_list;
                }
                ctx.realtarget_nchars = tstrlen(ctx.realtarget);
+       #ifdef __WIN32__
+              /* Strip trailing slashes.  If we don't do this, we may create a
+               * path with multiple consecutive backslashes, which for some
+               * reason causes Windows to report that the file cannot be found.
+               */
+               while (ctx.realtarget_nchars >= 2
+                      && ctx.realtarget[ctx.realtarget_nchars - 1] == L'\\'
+                      && ctx.realtarget[ctx.realtarget_nchars - 2] != L':')
+               {
+                       ctx.realtarget[--ctx.realtarget_nchars] = L'\0';
+               }
+       #endif
        }
 
        if (progress_func) {
@@ -2744,6 +2785,13 @@ check_extract_flags(const WIMStruct *wim, int *extract_flags_p)
        }
 #endif
 
+#ifndef __WIN32__
+       if (extract_flags & WIMLIB_EXTRACT_FLAG_WIMBOOT) {
+               ERROR("WIMBoot extraction is only supported on Windows!");
+               return WIMLIB_ERR_UNSUPPORTED;
+       }
+#endif
+
        if ((extract_flags & (WIMLIB_EXTRACT_FLAG_RPFIX |
                              WIMLIB_EXTRACT_FLAG_NORPFIX |
                              WIMLIB_EXTRACT_FLAG_IMAGEMODE)) ==
@@ -2849,8 +2897,7 @@ do_wimlib_extract_paths(WIMStruct *wim, int image, const tchar *target,
                return ret;
 
        if ((extract_flags & (WIMLIB_EXTRACT_FLAG_NTFS |
-                             WIMLIB_EXTRACT_FLAG_NO_PRESERVE_DIR_STRUCTURE |
-                             WIMLIB_EXTRACT_FLAG_FILEMODE)) ==
+                             WIMLIB_EXTRACT_FLAG_NO_PRESERVE_DIR_STRUCTURE)) ==
            (WIMLIB_EXTRACT_FLAG_NO_PRESERVE_DIR_STRUCTURE))
        {
                ret = mkdir_if_needed(target);
@@ -2931,7 +2978,7 @@ extract_single_image(WIMStruct *wim, int image,
                     const tchar *target, int extract_flags,
                     wimlib_progress_func_t progress_func)
 {
-       const tchar *path = T("");
+       const tchar *path = WIMLIB_WIM_ROOT_PATH;
        extract_flags |= WIMLIB_EXTRACT_FLAG_IMAGEMODE;
        return do_wimlib_extract_paths(wim, image, target, &path, 1,
                                       extract_flags, progress_func);
@@ -3040,67 +3087,6 @@ do_wimlib_extract_image(WIMStruct *wim,
  *                          Extraction API                                  *
  ****************************************************************************/
 
-/* Note: new code should use wimlib_extract_paths() instead of
- * wimlib_extract_files() if possible.  */
-WIMLIBAPI int
-wimlib_extract_files(WIMStruct *wim, int image,
-                    const struct wimlib_extract_command *cmds, size_t num_cmds,
-                    int default_extract_flags,
-                    wimlib_progress_func_t progress_func)
-{
-       int all_flags = 0;
-       int link_flags;
-       int ret;
-
-       if (num_cmds == 0)
-               return 0;
-
-       default_extract_flags |= WIMLIB_EXTRACT_FLAG_NO_PRESERVE_DIR_STRUCTURE;
-
-       for (size_t i = 0; i < num_cmds; i++) {
-               int cmd_flags = (cmds[i].extract_flags |
-                                default_extract_flags);
-
-               if (cmd_flags & ~WIMLIB_EXTRACT_MASK_PUBLIC)
-                       return WIMLIB_ERR_INVALID_PARAM;
-
-               int cmd_link_flags = (cmd_flags & (WIMLIB_EXTRACT_FLAG_SYMLINK |
-                                                  WIMLIB_EXTRACT_FLAG_HARDLINK));
-               if (i == 0) {
-                       link_flags = cmd_link_flags;
-               } else {
-                       if (cmd_link_flags != link_flags) {
-                               ERROR("The same symlink or hardlink extraction mode "
-                                     "must be set on all extraction commands!");
-                               return WIMLIB_ERR_INVALID_PARAM;
-                       }
-               }
-               all_flags |= cmd_flags;
-       }
-       if (all_flags & WIMLIB_EXTRACT_FLAG_GLOB_PATHS) {
-               ERROR("Glob paths not supported for wimlib_extract_files(). "
-                     "Use wimlib_extract_paths() instead.");
-               return WIMLIB_ERR_INVALID_PARAM;
-       }
-
-       for (size_t i = 0; i < num_cmds; i++) {
-               int extract_flags = (cmds[i].extract_flags |
-                                    default_extract_flags);
-               const tchar *target = cmds[i].fs_dest_path;
-               const tchar *wim_source_path = cmds[i].wim_source_path;
-
-               ret = do_wimlib_extract_paths(wim, image, target,
-                                             &wim_source_path, 1,
-                                             extract_flags | WIMLIB_EXTRACT_FLAG_FILEMODE,
-                                             progress_func);
-               if (ret)
-                       break;
-       }
-
-       clear_lte_extracted_file(wim, all_flags);
-       return ret;
-}
-
 WIMLIBAPI int
 wimlib_extract_paths(WIMStruct *wim, int image, const tchar *target,
                     const tchar * const *paths, size_t num_paths,