]> wimlib.net Git - wimlib/blobdiff - src/win32_apply.c
win32_common: add winnt_fsctl() helper method
[wimlib] / src / win32_apply.c
index faacd718b7e9178e0d00610a7bd4aa57ea1b3313..afa11ac76b160c82aec401360d907245aefc7fbf 100644 (file)
@@ -3,7 +3,7 @@
  */
 
 /*
- * Copyright (C) 2013, 2014, 2015 Eric Biggers
+ * Copyright (C) 2013-2016 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
@@ -1092,6 +1092,9 @@ adjust_compression_attribute(HANDLE h, const struct wim_dentry *dentry,
 {
        const bool compressed = (dentry->d_inode->i_attributes &
                                 FILE_ATTRIBUTE_COMPRESSED);
+       FILE_BASIC_INFORMATION info;
+       USHORT compression_state;
+       NTSTATUS status;
 
        if (ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_NO_ATTRIBUTES)
                return 0;
@@ -1099,10 +1102,6 @@ adjust_compression_attribute(HANDLE h, const struct wim_dentry *dentry,
        if (!ctx->common.supported_features.compressed_files)
                return 0;
 
-       FILE_BASIC_INFORMATION info;
-       NTSTATUS status;
-       USHORT compression_state;
-       DWORD bytes_returned;
 
        /* Get current attributes  */
        status = (*func_NtQueryInformationFile)(h, &ctx->iosb,
@@ -1122,14 +1121,12 @@ adjust_compression_attribute(HANDLE h, const struct wim_dentry *dentry,
        else
                compression_state = COMPRESSION_FORMAT_NONE;
 
-       /* Note: don't use NtFsControlFile() here unless prepared to handle
-        * STATUS_PENDING.  */
-       if (DeviceIoControl(h, FSCTL_SET_COMPRESSION,
-                           &compression_state, sizeof(USHORT), NULL, 0,
-                           &bytes_returned, NULL))
-               return 0;
+       status = winnt_fsctl(h, FSCTL_SET_COMPRESSION,
+                            &compression_state, sizeof(USHORT), NULL, 0, NULL);
+       if (NT_SUCCESS(status))
+               return status;
 
-       win32_error(GetLastError(), L"Can't %s compression attribute on \"%ls\"",
+       winnt_error(status, L"Can't %s compression attribute on \"%ls\"",
                    (compressed ? "set" : "clear"), current_path(ctx));
        return WIMLIB_ERR_SET_ATTRIBUTES;
 }
@@ -1347,7 +1344,7 @@ retry:
  * A wrapper around NtCreateFile() to make it slightly more usable...
  * This uses the path currently constructed in ctx->pathbuf.
  *
- * Also, we always specify FILE_OPEN_FOR_BACKUP_INTENT and
+ * Also, we always specify SYNCHRONIZE access, FILE_OPEN_FOR_BACKUP_INTENT, and
  * FILE_OPEN_REPARSE_POINT.
  */
 static NTSTATUS
@@ -1360,7 +1357,7 @@ do_create_file(PHANDLE FileHandle,
               struct win32_apply_ctx *ctx)
 {
        return (*func_NtCreateFile)(FileHandle,
-                                   DesiredAccess,
+                                   DesiredAccess | SYNCHRONIZE,
                                    &ctx->attr,
                                    &ctx->iosb,
                                    AllocationSize,
@@ -1525,10 +1522,8 @@ do_set_reparse_point(const struct wim_dentry *dentry,
        if (!NT_SUCCESS(status))
                goto fail;
 
-       status = (*func_NtFsControlFile)(h, NULL, NULL, NULL,
-                                        &ctx->iosb, FSCTL_SET_REPARSE_POINT,
-                                        (void *)rpbuf, rpbuflen,
-                                        NULL, 0);
+       status = winnt_fsctl(h, FSCTL_SET_REPARSE_POINT,
+                            rpbuf, rpbuflen, NULL, 0, NULL);
        (*func_NtClose)(h);
 
        if (NT_SUCCESS(status))
@@ -1648,8 +1643,24 @@ retry:
                                goto retry;
                        }
                }
-               winnt_error(status, L"Can't create directory \"%ls\"",
-                           current_path(ctx));
+               const wchar_t *path = current_path(ctx);
+               winnt_error(status, L"Can't create directory \"%ls\"", path);
+
+               /* Check for known issue with WindowsApps directory.  */
+               if (status == STATUS_ACCESS_DENIED &&
+                   (wcsstr(path, L"\\WindowsApps\\") ||
+                    wcsstr(path, L"\\InfusedApps\\"))) {
+                       ERROR(
+"You seem to be trying to extract files to the WindowsApps directory.\n"
+"        Windows 8.1 and later use new file permissions in this directory that\n"
+"        cannot be overridden, even by backup/restore programs.  To extract your\n"
+"        files anyway, you need to choose a different target directory, delete\n"
+"        the WindowsApps directory entirely, reformat the volume, do the\n"
+"        extraction from a non-broken operating system such as Windows 7 or\n"
+"        Linux, or wait for Microsoft to fix the design flaw in their operating\n"
+"        system.  This is *not* a bug in wimlib.  See this thread for more\n"
+"        information: https://wimlib.net/forums/viewtopic.php?f=1&t=261");
+               }
                return WIMLIB_ERR_MKDIR;
        }
 
@@ -2109,6 +2120,26 @@ try_rpfix(struct reparse_buffer_disk *rpbuf, u16 *rpbuflen_p,
 
        target_ntpath_nchars = ctx->target_ntpath.Length / sizeof(wchar_t);
 
+       /* If the target directory is a filesystem root, such as \??\C:\, then
+        * it already will have a trailing slash.  Don't include this slash if
+        * we are already adding slashes via 'relpath'.  This prevents an extra
+        * slash from being generated each time the link is extracted.  And
+        * unlike on UNIX, the number of slashes in paths on Windows can be
+        * significant; Windows won't understand the link target if it contains
+        * too many slashes.  */
+       if (target_ntpath_nchars > 0 && relpath_nchars > 0 &&
+           ctx->target_ntpath.Buffer[target_ntpath_nchars - 1] == L'\\')
+               target_ntpath_nchars--;
+
+       /* Also remove extra slashes from the beginning of 'relpath'.  Normally
+        * this isn't needed, but this is here to make the extra slash(es) added
+        * by wimlib pre-v1.9.1 get removed automatically.  */
+       while (relpath_nchars >= 2 &&
+              relpath[0] == L'\\' && relpath[1] == L'\\') {
+               relpath++;
+               relpath_nchars--;
+       }
+
        fixed_subst_name_nchars = target_ntpath_nchars + relpath_nchars;
 
        wchar_t fixed_subst_name[fixed_subst_name_nchars];
@@ -2342,7 +2373,6 @@ static NTSTATUS
 set_system_compression(HANDLE h, int format)
 {
        NTSTATUS status;
-       IO_STATUS_BLOCK iosb;
        struct {
                struct wof_external_info wof_info;
                struct file_provider_external_info file_info;
@@ -2363,9 +2393,8 @@ set_system_compression(HANDLE h, int format)
         * versions of Windows (before Windows 10?).  This can be a problem if
         * the WOFADK driver is being used rather than the regular WOF, since
         * WOFADK can be used on older versions of Windows.  */
-       status = (*func_NtFsControlFile)(h, NULL, NULL, NULL, &iosb,
-                                        FSCTL_SET_EXTERNAL_BACKING,
-                                        &in, sizeof(in), NULL, 0);
+       status = winnt_fsctl(h, FSCTL_SET_EXTERNAL_BACKING,
+                            &in, sizeof(in), NULL, 0, NULL);
 
        if (status == 0xC000046F) /* "Compressing this object would not save space."  */
                return STATUS_SUCCESS;