Pay attention to PrepopulateList during WIMBoot application
authorEric Biggers <ebiggers3@gmail.com>
Thu, 24 Apr 2014 18:01:01 +0000 (13:01 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Thu, 24 Apr 2014 18:05:31 +0000 (13:05 -0500)
include/wimlib/apply.h
include/wimlib/capture.h
include/wimlib/textfile.h
src/capture_common.c
src/extract.c
src/ntfs-3g_apply.c
src/pathlist.c
src/textfile.c
src/unix_apply.c
src/update_image.c
src/win32_apply.c

index a93bc7e..7b4ffe3 100644 (file)
@@ -72,7 +72,7 @@ struct apply_operations {
        /* REQUIRED:  Extract unnamed data stream.  */
        int (*extract_unnamed_stream)
                (file_spec_t file, struct wim_lookup_table_entry *lte,
-                struct apply_ctx *ctx);
+                struct apply_ctx *ctx, struct wim_dentry *dentry);
 
        /* OPTIONAL:  Extracted named data stream.  In start_extract(), set
         * ctx->supported_features.alternate_data_streams if supported.  */
index 995a60f..aa9c4cd 100644 (file)
@@ -17,7 +17,7 @@ struct capture_config {
        struct string_set exclusion_exception_pats;
        tchar *prefix;
        size_t prefix_num_tchars;
-       tchar *buf;
+       void *buf;
 };
 
 /* Common parameters to implementations of building an in-memory dentry tree
@@ -65,13 +65,21 @@ do_capture_progress(struct add_image_params *params, int status,
                    const struct wim_inode *inode);
 
 extern int
-do_read_capture_config_file(const tchar *config_file, tchar *buf, size_t buflen,
-                           struct capture_config *config);
+mangle_pat(tchar *pat, const tchar *path, unsigned long line_no);
+
+extern int
+do_read_capture_config_file(const tchar *config_file, const void *buf,
+                           size_t bufsize, struct capture_config *config);
 
 extern void
 destroy_capture_config(struct capture_config *config);
 
 extern bool
+match_pattern(const tchar *path,
+             const tchar *path_basename,
+             const struct string_set *list);
+
+extern bool
 exclude_path(const tchar *path, size_t path_len,
             const struct capture_config *config,
             bool exclude_prefix);
index bc2068f..b4e3885 100644 (file)
@@ -24,29 +24,21 @@ struct text_file_section {
 };
 
 #define LOAD_TEXT_FILE_REMOVE_QUOTES 0x00000001
+#define LOAD_TEXT_FILE_NO_WARNINGS   0x00000002
 
 extern int
-do_load_text_file(const tchar *path, tchar *buf, size_t buflen, tchar **buf_ret,
+do_load_text_file(const tchar *path,
+                 const void *buf, size_t bufsize, void **mem_ret,
                  const struct text_file_section *pos_sections,
                  int num_pos_sections, int flags,
                  line_mangle_t mangle_line);
 
 static inline int
-load_text_file(const tchar *path, tchar **buf_ret,
+load_text_file(const tchar *path, void **mem_ret,
               const struct text_file_section *pos_sections,
               int num_pos_sections, line_mangle_t mangle_line)
 {
-       return do_load_text_file(path, NULL, 0, buf_ret,
-                                pos_sections, num_pos_sections,
-                                LOAD_TEXT_FILE_REMOVE_QUOTES, mangle_line);
-}
-
-static inline int
-load_text_buffer(tchar *buf, size_t buflen,
-                const struct text_file_section *pos_sections,
-                int num_pos_sections, line_mangle_t mangle_line)
-{
-       return do_load_text_file(NULL, buf, buflen, &buf,
+       return do_load_text_file(path, NULL, 0, mem_ret,
                                 pos_sections, num_pos_sections,
                                 LOAD_TEXT_FILE_REMOVE_QUOTES, mangle_line);
 }
index 35aaee6..00f8eab 100644 (file)
@@ -69,7 +69,7 @@ do_capture_progress(struct add_image_params *params, int status,
        }
 }
 
-static int
+int
 mangle_pat(tchar *pat, const tchar *path, unsigned long line_no)
 {
        if (!is_any_path_separator(pat[0]) &&
@@ -105,8 +105,8 @@ mangle_pat(tchar *pat, const tchar *path, unsigned long line_no)
 }
 
 int
-do_read_capture_config_file(const tchar *config_file, tchar *buf, size_t buflen,
-                           struct capture_config *config)
+do_read_capture_config_file(const tchar *config_file, const void *buf,
+                           size_t bufsize, struct capture_config *config)
 {
        int ret;
        struct text_file_section sections[] = {
@@ -115,14 +115,15 @@ do_read_capture_config_file(const tchar *config_file, tchar *buf, size_t buflen,
                {T("ExclusionException"),
                        &config->exclusion_exception_pats},
        };
+       void *mem;
 
-       ret = do_load_text_file(config_file, buf, buflen, &buf,
+       ret = do_load_text_file(config_file, buf, bufsize, &mem,
                                sections, ARRAY_LEN(sections),
                                LOAD_TEXT_FILE_REMOVE_QUOTES, mangle_pat);
        if (ret)
                return ret;
 
-       config->buf = buf;
+       config->buf = mem;
        return 0;
 }
 
@@ -134,7 +135,7 @@ destroy_capture_config(struct capture_config *config)
        FREE(config->buf);
 }
 
-static bool
+bool
 match_pattern(const tchar *path,
              const tchar *path_basename,
              const struct string_set *list)
index 3377072..c6a3b56 100644 (file)
@@ -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;
                        }
index 86a28c1..0d054ed 100644 (file)
@@ -284,7 +284,8 @@ out:
 static int
 ntfs_3g_extract_unnamed_stream(file_spec_t file,
                               struct wim_lookup_table_entry *lte,
-                              struct apply_ctx *ctx)
+                              struct apply_ctx *ctx,
+                              struct wim_dentry *_ignore)
 {
        return ntfs_3g_extract_stream(file, NULL, 0, lte, ctx);
 }
index c366ed7..1bb20cf 100644 (file)
@@ -40,7 +40,7 @@ read_path_list_file(const tchar *listfile,
                .name = T(""),
                .strings = &paths,
        };
-       tchar *buf;
+       void *buf;
        int ret;
 
        ret = load_text_file(listfile, &buf, &tmp, 1, NULL);
@@ -49,6 +49,6 @@ read_path_list_file(const tchar *listfile,
 
        *paths_ret = paths.strings;
        *num_paths_ret = paths.num_strings;
-       *mem_ret = (void *)buf;
+       *mem_ret = buf;
        return 0;
 }
index c42a172..a2b630a 100644 (file)
 #include <unistd.h>
 
 static int
-read_file_contents(const tchar *path, u8 **buf_ret, size_t *bufsize_ret)
+read_file_contents(const tchar *path, void **buf_ret, size_t *bufsize_ret)
 {
        int raw_fd;
        struct filedes fd;
        struct stat st;
-       u8 *buf;
+       void *buf;
        int ret;
        int errno_save;
 
@@ -87,20 +87,14 @@ read_file_contents(const tchar *path, u8 **buf_ret, size_t *bufsize_ret)
 }
 
 static int
-read_text_file_contents(const tchar *path,
-                       tchar **buf_ret, size_t *buflen_ret)
+translate_text_buffer(const u8 *buf_raw, size_t bufsize_raw,
+                     tchar **tstr_ret, size_t *tstr_nchars_ret)
 {
-       int ret;
-       u8 *buf_raw;
-       size_t bufsize_raw;
        size_t offset_raw;
        bool utf8;
        tchar *buf_tstr;
        size_t bufsize_tstr;
-
-       ret = read_file_contents(path, &buf_raw, &bufsize_raw);
-       if (ret)
-               return ret;
+       int ret;
 
        /* Guess the encoding: UTF-8 or UTF-16LE.  (Something weirder and you're
         * out of luck, sorry...)  */
@@ -144,6 +138,7 @@ read_text_file_contents(const tchar *path,
                        memcpy(buf_tstr, buf_raw + offset_raw, bufsize_tstr);
                        ((u8*)buf_tstr)[bufsize_tstr + 0] = 0;
                        ((u8*)buf_tstr)[bufsize_tstr + 1] = 0;
+                       ret = 0;
                } else {
                        ret = WIMLIB_ERR_NOMEM;
                }
@@ -153,12 +148,11 @@ read_text_file_contents(const tchar *path,
                                      &buf_tstr, &bufsize_tstr);
        #endif
        }
-       FREE(buf_raw);
        if (ret)
                return ret;
 
-       *buf_ret = buf_tstr;
-       *buflen_ret = bufsize_tstr / sizeof(tchar);
+       *tstr_ret = buf_tstr;
+       *tstr_nchars_ret = bufsize_tstr / sizeof(tchar);
        return 0;
 }
 
@@ -248,16 +242,22 @@ parse_text_file(const tchar *path, tchar *buf, size_t buflen,
                                }
                        }
                        line_begin[line_len - 1] = T(']');
-                       if (current_section < 0)
-                               WARNING("%"TS":%lu: Unrecognized section \"%"TS"\"",
-                                       path, line_no, line_begin);
+                       if (current_section < 0) {
+                               if (!(flags & LOAD_TEXT_FILE_NO_WARNINGS)) {
+                                       WARNING("%"TS":%lu: Unrecognized section \"%"TS"\"",
+                                               path, line_no, line_begin);
+                               }
+                       }
                        continue;
                }
 
                if (current_section < 0) {
-                       if (current_section == NOT_IN_SECTION)
-                               WARNING("%"TS":%lu: Not in a bracketed section!",
-                                       path, line_no);
+                       if (current_section == NOT_IN_SECTION) {
+                               if (!(flags & LOAD_TEXT_FILE_NO_WARNINGS)) {
+                                       WARNING("%"TS":%lu: Not in a bracketed section!",
+                                               path, line_no);
+                               }
+                       }
                        continue;
                }
 
@@ -300,7 +300,7 @@ parse_text_file(const tchar *path, tchar *buf, size_t buflen,
  *     If NULL, the data will be read from the @path file.  Otherwise the data
  *     will be read from this buffer, which must be newline-terminated.
  * @buflen
- *     Length of buffer in 'tchars'; ignored if @buf is NULL.
+ *     Length of buffer in bytes; ignored if @buf is NULL.
  * @buf_ret
  *     On success, a pointer to a buffer backing the parsed lines is stored
  *     here.  If @buf is not NULL, this will be @buf.  Otherwise, this will be
@@ -324,8 +324,8 @@ parse_text_file(const tchar *path, tchar *buf, size_t buflen,
  */
 int
 do_load_text_file(const tchar *path,
-                 tchar *buf, size_t buflen,
-                 tchar **buf_ret,
+                 const void *buf, size_t bufsize,
+                 void **mem_ret,
                  const struct text_file_section *pos_sections,
                  int num_pos_sections,
                  int flags,
@@ -333,29 +333,32 @@ do_load_text_file(const tchar *path,
 {
        int ret;
        bool pathmode = (buf == NULL);
+       tchar *tstr;
+       size_t tstr_nchars;
 
        if (pathmode) {
-               ret = read_text_file_contents(path, &buf, &buflen);
+               ret = read_file_contents(path, (void **)&buf, &bufsize);
                if (ret)
                        return ret;
-
-               /* Overwrite '\0' with '\n' to avoid special case of last line
-                * not terminated with '\n'.  */
-               buf[buflen++] = T('\n');
-       } else {
-               wimlib_assert(buflen > 0 && buf[buflen - 1] == T('\n'));
        }
 
-       ret = parse_text_file(path, buf, buflen, pos_sections,
+       ret = translate_text_buffer(buf, bufsize, &tstr, &tstr_nchars);
+       if (pathmode)
+               FREE((void *)buf);
+       if (ret)
+               return ret;
+
+       tstr[tstr_nchars++] = T('\n');
+
+       ret = parse_text_file(path, tstr, tstr_nchars, pos_sections,
                              num_pos_sections, flags, mangle_line);
        if (ret) {
                for (int i = 0; i < num_pos_sections; i++)
                        FREE(pos_sections[i].strings->strings);
-               if (pathmode)
-                       FREE(buf);
+               FREE(tstr);
                return ret;
        }
 
-       *buf_ret = buf;
+       *mem_ret = tstr;
        return 0;
 }
index 8d549f6..d188844 100644 (file)
@@ -115,7 +115,7 @@ unix_create_symlink(const tchar *oldpath, const tchar *newpath,
 static int
 unix_extract_unnamed_stream(file_spec_t file,
                            struct wim_lookup_table_entry *lte,
-                           struct apply_ctx *ctx)
+                           struct apply_ctx *ctx, struct wim_dentry *_ignore)
 {
        const char *path = file.path;
        struct filedes fd;
index 82aac7f..05861f2 100644 (file)
@@ -165,16 +165,14 @@ attach_branch(struct wim_dentry **root_p, struct wim_dentry *branch,
        }
 }
 
-const tchar wincfg[] =
-T(
+static const char wincfg[] =
 "[ExclusionList]\n"
 "/$ntfs.log\n"
 "/hiberfil.sys\n"
 "/pagefile.sys\n"
 "/System Volume Information\n"
 "/RECYCLER\n"
-"/Windows/CSC\n"
-);
+"/Windows/CSC\n";
 
 static int
 get_capture_config(const tchar *config_file, struct capture_config *config,
@@ -211,23 +209,11 @@ get_capture_config(const tchar *config_file, struct capture_config *config,
        }
 
        if (add_flags & WIMLIB_ADD_FLAG_WINCONFIG) {
-
                /* Use Windows default.  */
-
-               tchar *wincfg_copy;
-               const size_t wincfg_len = ARRAY_LEN(wincfg) - 1;
-
                if (config_file)
                        return WIMLIB_ERR_INVALID_PARAM;
-
-               wincfg_copy = memdup(wincfg, wincfg_len * sizeof(wincfg[0]));
-               if (!wincfg_copy)
-                       return WIMLIB_ERR_NOMEM;
-
-               ret = do_read_capture_config_file(T("wincfg"), wincfg_copy,
-                                                 wincfg_len, config);
-               if (ret)
-                       FREE(wincfg_copy);
+               ret = do_read_capture_config_file(T("wincfg"), wincfg,
+                                                 sizeof(wincfg) - 1, config);
        } else if (config_file) {
                /* Use the specified configuration file.  */
                ret = do_read_capture_config_file(config_file, NULL, 0, config);
index 87582d6..2b0d5a4 100644 (file)
 #include "wimlib/win32_common.h"
 
 #include "wimlib/apply.h"
+#include "wimlib/capture.h"
+#include "wimlib/dentry.h"
 #include "wimlib/error.h"
 #include "wimlib/lookup_table.h"
+#include "wimlib/paths.h"
+#include "wimlib/textfile.h"
 #include "wimlib/xml.h"
 #include "wimlib/wim.h"
 #include "wimlib/wimboot.h"
@@ -49,6 +53,110 @@ ctx_get_data_source_id(const struct apply_ctx *ctx)
        return (u32)ctx->private[0] | ((u64)(u32)ctx->private[1] << 32);
 }
 
+static void
+set_prepopulate_pats(struct apply_ctx *ctx, struct string_set *s)
+{
+       ctx->private[2] = (intptr_t)s;
+}
+
+static struct string_set *
+alloc_prepopulate_pats(struct apply_ctx *ctx)
+{
+       struct string_set *s = CALLOC(1, sizeof(*s));
+       set_prepopulate_pats(ctx, s);
+       return s;
+}
+
+static struct string_set *
+get_prepopulate_pats(struct apply_ctx *ctx)
+{
+       return (struct string_set *)(ctx->private[2]);
+}
+
+static void
+free_prepopulate_pats(struct apply_ctx *ctx)
+{
+       struct string_set *s;
+
+       s = get_prepopulate_pats(ctx);
+       if (s) {
+               FREE(s->strings);
+               FREE(s);
+       }
+       set_prepopulate_pats(ctx, NULL);
+
+       FREE((void *)ctx->private[3]);
+       ctx->private[3] = (intptr_t)NULL;
+}
+
+static int
+load_prepopulate_pats(struct apply_ctx *ctx)
+{
+       int ret;
+       struct wim_dentry *dentry;
+       struct wim_lookup_table_entry *lte;
+       struct string_set *s;
+       const tchar *path = WIMLIB_WIM_PATH_SEPARATOR_STRING T("Windows")
+                           WIMLIB_WIM_PATH_SEPARATOR_STRING T("System32")
+                           WIMLIB_WIM_PATH_SEPARATOR_STRING T("WimBootCompress.ini");
+       void *buf;
+       void *mem;
+       struct text_file_section sec;
+
+       dentry = get_dentry(ctx->wim, path, WIMLIB_CASE_INSENSITIVE);
+       if (!dentry ||
+           (dentry->d_inode->i_attributes & (FILE_ATTRIBUTE_DIRECTORY |
+                                             FILE_ATTRIBUTE_REPARSE_POINT |
+                                             FILE_ATTRIBUTE_ENCRYPTED)) ||
+           !(lte = inode_unnamed_lte(dentry->d_inode, ctx->wim->lookup_table)))
+       {
+               WARNING("%"TS" does not exist in WIM image!", path);
+               return WIMLIB_ERR_PATH_DOES_NOT_EXIST;
+       }
+
+       ret = read_full_stream_into_alloc_buf(lte, &buf);
+       if (ret)
+               return ret;
+
+       s = alloc_prepopulate_pats(ctx);
+       if (!s) {
+               FREE(buf);
+               return WIMLIB_ERR_NOMEM;
+       }
+
+       sec.name = T("PrepopulateList");
+       sec.strings = s;
+
+       ret = do_load_text_file(path, buf, lte->size, &mem, &sec, 1,
+                               LOAD_TEXT_FILE_REMOVE_QUOTES |
+                                       LOAD_TEXT_FILE_NO_WARNINGS,
+                               mangle_pat);
+       FREE(buf);
+       if (ret) {
+               free_prepopulate_pats(ctx);
+               return ret;
+       }
+       ctx->private[3] = (intptr_t)mem;
+       return 0;
+}
+
+static bool
+in_prepopulate_list(struct wim_dentry *dentry,
+                   struct apply_ctx *ctx)
+{
+       struct string_set *pats;
+       const tchar *path;
+
+       pats = get_prepopulate_pats(ctx);
+       if (!pats)
+               return false;
+       path = dentry_full_path(dentry);
+       if (!path)
+               return false;
+
+       return match_pattern(path, path_basename(path), pats);
+}
+
 static int
 win32_start_extract(const wchar_t *path, struct apply_ctx *ctx)
 {
@@ -97,6 +205,10 @@ win32_start_extract(const wchar_t *path, struct apply_ctx *ctx)
 
        if (ctx->extract_flags & WIMLIB_EXTRACT_FLAG_WIMBOOT) {
 
+               ret = load_prepopulate_pats(ctx);
+               if (ret == WIMLIB_ERR_NOMEM)
+                       return ret;
+
                u64 data_source_id;
 
                if (!wim_info_get_wimboot(ctx->wim->wim_info,
@@ -106,8 +218,10 @@ win32_start_extract(const wchar_t *path, struct apply_ctx *ctx)
                ret = wimboot_alloc_data_source_id(ctx->wim->filename,
                                                   ctx->wim->current_image,
                                                   path, &data_source_id);
-               if (ret)
+               if (ret) {
+                       free_prepopulate_pats(ctx);
                        return ret;
+               }
 
                ctx_save_data_source_id(ctx, data_source_id);
        }
@@ -115,6 +229,13 @@ win32_start_extract(const wchar_t *path, struct apply_ctx *ctx)
        return 0;
 }
 
+static int
+win32_finish_extract(struct apply_ctx *ctx)
+{
+       free_prepopulate_pats(ctx);
+       return 0;
+}
+
 /* Delete a non-directory file, working around Windows quirks.  */
 static BOOL
 win32_delete_file_wrapper(const wchar_t *path)
@@ -297,12 +418,14 @@ error:
 static int
 win32_extract_unnamed_stream(file_spec_t file,
                             struct wim_lookup_table_entry *lte,
-                            struct apply_ctx *ctx)
+                            struct apply_ctx *ctx,
+                            struct wim_dentry *dentry)
 {
        if (ctx->extract_flags & WIMLIB_EXTRACT_FLAG_WIMBOOT
            && lte
            && lte->resource_location == RESOURCE_IN_WIM
-           && lte->rspec->wim == ctx->wim)
+           && lte->rspec->wim == ctx->wim
+           && !in_prepopulate_list(dentry, ctx))
        {
                return wimboot_set_pointer(file.path,
                                           ctx_get_data_source_id(ctx),
@@ -767,6 +890,8 @@ const struct apply_operations win32_apply_ops = {
 
        .target_is_root           = win32_path_is_root_of_drive,
        .start_extract            = win32_start_extract,
+       .finish_extract           = win32_finish_extract,
+       .abort_extract            = win32_finish_extract,
        .create_file              = win32_create_file,
        .create_directory         = win32_create_directory,
        .create_hardlink          = win32_create_hardlink,