]> wimlib.net Git - wimlib/blobdiff - src/extract.c
Add support for a data recovery mode
[wimlib] / src / extract.c
index a39c1c02210815b503f9c29e81a1806eda1a114c..0e5d4ec4c900c1aab13d23bdd4f905c51afb6b8e 100644 (file)
@@ -6,7 +6,7 @@
  */
 
 /*
- * Copyright (C) 2012-2016 Eric Biggers
+ * Copyright (C) 2012-2018 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
@@ -63,6 +63,7 @@
 #include "wimlib/unix_data.h"
 #include "wimlib/wim.h"
 #include "wimlib/win32.h" /* for realpath() equivalent */
+#include "wimlib/xattr.h"
 #include "wimlib/xml.h"
 
 #define WIMLIB_EXTRACT_FLAG_FROM_PIPE   0x80000000
@@ -71,6 +72,7 @@
 /* Keep in sync with wimlib.h  */
 #define WIMLIB_EXTRACT_MASK_PUBLIC                             \
        (WIMLIB_EXTRACT_FLAG_NTFS                       |       \
+        WIMLIB_EXTRACT_FLAG_RECOVER_DATA               |       \
         WIMLIB_EXTRACT_FLAG_UNIX_DATA                  |       \
         WIMLIB_EXTRACT_FLAG_NO_ACLS                    |       \
         WIMLIB_EXTRACT_FLAG_STRICT_ACLS                |       \
@@ -309,7 +311,9 @@ read_blobs_from_pipe(struct apply_ctx *ctx, const struct read_blob_callbacks *cb
                    && (blob->out_refcnt))
                {
                        wim_reshdr_to_desc_and_blob(&reshdr, ctx->wim, &rdesc, blob);
-                       ret = read_blob_with_sha1(blob, cbs);
+                       ret = read_blob_with_sha1(blob, cbs,
+                                                 ctx->extract_flags &
+                                                 WIMLIB_EXTRACT_FLAG_RECOVER_DATA);
                        blob_unset_is_located_in_wim_resource(blob);
                        if (ret)
                                return ret;
@@ -503,18 +507,39 @@ extract_from_tmpfile(const tchar *tmpfile_name,
 
        for (u32 i = 0; i < orig_blob->out_refcnt; i++) {
                tmpfile_blob.inline_blob_extraction_targets[0] = targets[i];
-               ret = read_blob_with_cbs(&tmpfile_blob, cbs);
+               ret = read_blob_with_cbs(&tmpfile_blob, cbs, false);
                if (ret)
                        return ret;
        }
        return 0;
 }
 
+static void
+warn_about_corrupted_file(struct wim_dentry *dentry,
+                         const struct wim_inode_stream *stream)
+{
+       WARNING("Corruption in %s\"%"TS"\"!  Extracting anyway since data recovery mode is enabled.",
+               stream_is_unnamed_data_stream(stream) ? "" : "alternate stream of ",
+               dentry_full_path(dentry));
+}
+
 static int
 end_extract_blob(struct blob_descriptor *blob, int status, void *_ctx)
 {
        struct apply_ctx *ctx = _ctx;
 
+       if ((ctx->extract_flags & WIMLIB_EXTRACT_FLAG_RECOVER_DATA) &&
+           !status && blob->corrupted) {
+               const struct blob_extraction_target *targets =
+                       blob_extraction_targets(blob);
+               for (u32 i = 0; i < blob->out_refcnt; i++) {
+                       struct wim_dentry *dentry =
+                               inode_first_extraction_dentry(targets[i].inode);
+
+                       warn_about_corrupted_file(dentry, targets[i].stream);
+               }
+       }
+
        if (unlikely(filedes_valid(&ctx->tmpfile_fd))) {
                filedes_close(&ctx->tmpfile_fd);
                if (!status)
@@ -559,10 +584,15 @@ extract_blob_list(struct apply_ctx *ctx, const struct read_blob_callbacks *cbs)
        if (ctx->extract_flags & WIMLIB_EXTRACT_FLAG_FROM_PIPE) {
                return read_blobs_from_pipe(ctx, &wrapper_cbs);
        } else {
+               int flags = VERIFY_BLOB_HASHES;
+
+               if (ctx->extract_flags & WIMLIB_EXTRACT_FLAG_RECOVER_DATA)
+                       flags |= RECOVER_DATA;
+
                return read_blob_list(&ctx->blob_list,
                                      offsetof(struct blob_descriptor,
                                               extraction_list),
-                                     &wrapper_cbs, VERIFY_BLOB_HASHES);
+                                     &wrapper_cbs, flags);
        }
 }
 
@@ -573,11 +603,13 @@ extract_blob_list(struct apply_ctx *ctx, const struct read_blob_callbacks *cbs)
  * unnamed data stream only.  */
 static int
 extract_dentry_to_stdout(struct wim_dentry *dentry,
-                        const struct blob_table *blob_table)
+                        const struct blob_table *blob_table, int extract_flags)
 {
        struct wim_inode *inode = dentry->d_inode;
        struct blob_descriptor *blob;
        struct filedes _stdout;
+       bool recover = (extract_flags & WIMLIB_EXTRACT_FLAG_RECOVER_DATA);
+       int ret;
 
        if (inode->i_attributes & (FILE_ATTRIBUTE_REPARSE_POINT |
                                   FILE_ATTRIBUTE_DIRECTORY |
@@ -597,15 +629,23 @@ extract_dentry_to_stdout(struct wim_dentry *dentry,
        }
 
        filedes_init(&_stdout, STDOUT_FILENO);
-       return extract_blob_to_fd(blob, &_stdout);
+       ret = extract_blob_to_fd(blob, &_stdout, recover);
+       if (ret)
+               return ret;
+       if (recover && blob->corrupted)
+               warn_about_corrupted_file(dentry,
+                                         inode_get_unnamed_data_stream(inode));
+       return 0;
 }
 
 static int
 extract_dentries_to_stdout(struct wim_dentry **dentries, size_t num_dentries,
-                          const struct blob_table *blob_table)
+                          const struct blob_table *blob_table,
+                          int extract_flags)
 {
        for (size_t i = 0; i < num_dentries; i++) {
-               int ret = extract_dentry_to_stdout(dentries[i], blob_table);
+               int ret = extract_dentry_to_stdout(dentries[i], blob_table,
+                                                  extract_flags);
                if (ret)
                        return ret;
        }
@@ -1224,6 +1264,8 @@ inode_tally_features(const struct wim_inode *inode,
                features->unix_data++;
        if (inode_has_object_id(inode))
                features->object_ids++;
+       if (inode_has_xattrs(inode))
+               features->xattrs++;
 }
 
 /* Tally features necessary to extract a dentry and the corresponding inode.  */
@@ -1361,19 +1403,32 @@ do_feature_check(const struct wim_features *required_features,
                WARNING("Ignoring Windows NT security descriptors of %lu files",
                        required_features->security_descriptors);
 
-       /* UNIX data.  */
-       if ((extract_flags & WIMLIB_EXTRACT_FLAG_UNIX_DATA) &&
-           required_features->unix_data && !supported_features->unix_data)
+       /* Standard UNIX metadata */
+       if (required_features->unix_data &&
+           (!supported_features->unix_data ||
+            !(extract_flags & WIMLIB_EXTRACT_FLAG_UNIX_DATA)))
        {
-               ERROR("Extraction backend does not support UNIX data!");
-               return WIMLIB_ERR_UNSUPPORTED;
+               if (extract_flags & WIMLIB_EXTRACT_FLAG_UNIX_DATA) {
+                       ERROR("Requested UNIX metadata extraction, but "
+                             "extraction backend does not support it!");
+                       return WIMLIB_ERR_UNSUPPORTED;
+               }
+               WARNING("Ignoring UNIX metadata (uid/gid/mode/rdev) of %lu files%"TS,
+                       required_features->unix_data,
+                       (supported_features->unix_data ?
+                        T("\n          (use --unix-data mode to extract these)") : T("")));
        }
 
-       if (required_features->unix_data &&
-           !(extract_flags & WIMLIB_EXTRACT_FLAG_UNIX_DATA))
+       /* Extended attributes */
+       if (required_features->xattrs &&
+           (!supported_features->xattrs ||
+            (supported_features->unix_data &&
+             !(extract_flags & WIMLIB_EXTRACT_FLAG_UNIX_DATA))))
        {
-               WARNING("Ignoring UNIX metadata of %lu files",
-                       required_features->unix_data);
+               WARNING("Ignoring extended attributes of %lu files%"TS,
+                       required_features->xattrs,
+                       (supported_features->xattrs ?
+                        T("\n          (use --unix-data mode to extract these)") : T("")));
        }
 
        /* Object IDs.  */
@@ -1430,7 +1485,8 @@ extract_trees(WIMStruct *wim, struct wim_dentry **trees, size_t num_trees,
 
        if (extract_flags & WIMLIB_EXTRACT_FLAG_TO_STDOUT) {
                ret = extract_dentries_to_stdout(trees, num_trees,
-                                                wim->blob_table);
+                                                wim->blob_table,
+                                                extract_flags);
                goto out;
        }
 
@@ -1914,7 +1970,7 @@ wimlib_extract_pathlist(WIMStruct *wim, int image, const tchar *target,
        ret = read_path_list_file(path_list_file, &paths, &num_paths, &mem);
        if (ret) {
                ERROR("Failed to read path list file \"%"TS"\"",
-                     path_list_file);
+                     path_list_file ? path_list_file : T("<stdin>"));
                return ret;
        }