]> wimlib.net Git - wimlib/blobdiff - src/extract.c
extract: track READONLY attribute in supported_features
[wimlib] / src / extract.c
index 417300b769903f6f7ac86eb7d80abd0fcdf7f7b2..c1a5adb62aa095417b3b74874385c96456dfa86e 100644 (file)
 #include "wimlib/metadata.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.  */
@@ -341,30 +346,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))) {
@@ -580,8 +564,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 +660,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 +681,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;
 }
 
@@ -1001,10 +978,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?  */
@@ -1095,12 +1073,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) {
@@ -1178,9 +1158,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)
@@ -1192,6 +1174,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",
@@ -1408,12 +1394,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);
                }
        }
 
@@ -1507,6 +1493,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 |
@@ -1523,22 +1537,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;
@@ -1567,6 +1565,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,
@@ -1609,20 +1632,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;
@@ -1694,7 +1707,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
@@ -1702,9 +1716,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;
@@ -1860,7 +1873,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;
@@ -1924,6 +1937,7 @@ wimlib_extract_image_from_pipe_with_progress(int pipe_fd,
                        goto out_wimlib_free;
                wim_reshdr_to_desc_and_blob(&reshdr, pwm, metadata_rdesc,
                                            imd->metadata_blob);
+               pwm->refcnt++;
 
                if (i == image) {
                        /* Metadata resource is for the image being extracted.
@@ -1931,7 +1945,6 @@ wimlib_extract_image_from_pipe_with_progress(int pipe_fd,
                        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.  */