]> wimlib.net Git - wimlib/blobdiff - src/extract.c
mount_image.c: add fallback definitions of RENAME_* constants
[wimlib] / src / extract.c
index cd1dd2c1ca0ebb319066db5c02c5fcacff3ba84b..24b53cbea10a2e9253acac22fe8867cd5929501f 100644 (file)
@@ -19,7 +19,7 @@
  * details.
  *
  * You should have received a copy of the GNU Lesser General Public License
- * along with this file; if not, see http://www.gnu.org/licenses/.
+ * along with this file; if not, see https://www.gnu.org/licenses/.
  */
 
 /*
@@ -72,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                |       \
@@ -310,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;
@@ -384,7 +387,7 @@ create_temporary_file(struct filedes *fd_ret, tchar **name_ret)
        tchar *name;
        int raw_fd;
 
-#ifdef __WIN32__
+#ifdef _WIN32
 retry:
        name = _wtempnam(NULL, L"wimlib");
        if (!name) {
@@ -397,7 +400,7 @@ retry:
                FREE(name);
                goto retry;
        }
-#else /* __WIN32__ */
+#else /* _WIN32 */
        const char *tmpdir = getenv("TMPDIR");
        if (!tmpdir)
                tmpdir = P_tmpdir;
@@ -406,7 +409,7 @@ retry:
                return WIMLIB_ERR_NOMEM;
        sprintf(name, "%s/wimlibXXXXXX", tmpdir);
        raw_fd = mkstemp(name);
-#endif /* !__WIN32__ */
+#endif /* !_WIN32 */
 
        if (raw_fd < 0) {
                ERROR_WITH_ERRNO("Failed to create temporary file "
@@ -504,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)
@@ -560,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);
        }
 }
 
@@ -574,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 |
@@ -598,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;
        }
@@ -765,7 +804,7 @@ destroy_blob_list(struct list_head *blob_list)
                        FREE(blob->blob_extraction_targets);
 }
 
-#ifdef __WIN32__
+#ifdef _WIN32
 static const utf16lechar replacement_char = cpu_to_le16(0xfffd);
 #else
 static const utf16lechar replacement_char = cpu_to_le16('?');
@@ -780,7 +819,7 @@ file_name_valid(utf16lechar *name, size_t num_chars, bool fix)
                return true;
        for (i = 0; i < num_chars; i++) {
                switch (le16_to_cpu(name[i])) {
-       #ifdef __WIN32__
+       #ifdef _WIN32
                case '\x01'...'\x1F':
                case '\\':
                case ':':
@@ -1428,7 +1467,7 @@ select_apply_operations(int extract_flags)
        if (extract_flags & WIMLIB_EXTRACT_FLAG_NTFS)
                return &ntfs_3g_apply_ops;
 #endif
-#ifdef __WIN32__
+#ifdef _WIN32
        return &win32_apply_ops;
 #else
        return &unix_apply_ops;
@@ -1446,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;
        }
 
@@ -1585,7 +1625,7 @@ mkdir_if_needed(const tchar *target)
        if (errno == EEXIST)
                return 0;
 
-#ifdef __WIN32__
+#ifdef _WIN32
        /* _wmkdir() fails with EACCES if called on a drive root directory.  */
        if (errno == EACCES)
                return 0;
@@ -1624,7 +1664,7 @@ check_extract_flags(const WIMStruct *wim, int *extract_flags_p)
 #endif
 
        if (extract_flags & WIMLIB_EXTRACT_FLAG_WIMBOOT) {
-#ifdef __WIN32__
+#ifdef _WIN32
                if (!wim->filename)
                        return WIMLIB_ERR_NO_FILENAME;
 #else
@@ -1638,7 +1678,7 @@ check_extract_flags(const WIMStruct *wim, int *extract_flags_p)
                             WIMLIB_EXTRACT_FLAG_COMPACT_XPRESS16K |
                             WIMLIB_EXTRACT_FLAG_COMPACT_LZX))
        {
-       #ifdef __WIN32__
+       #ifdef _WIN32
                int count = 0;
                count += ((extract_flags & WIMLIB_EXTRACT_FLAG_COMPACT_XPRESS4K) != 0);
                count += ((extract_flags & WIMLIB_EXTRACT_FLAG_COMPACT_XPRESS8K) != 0);
@@ -1831,7 +1871,7 @@ extract_single_image(WIMStruct *wim, int image,
 }
 
 static const tchar * const filename_forbidden_chars =
-#ifdef __WIN32__
+#ifdef _WIN32
 T("<>:\"/\\|?*");
 #else
 T("/");
@@ -1930,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;
        }