]> wimlib.net Git - wimlib/blobdiff - src/win32_apply.c
Improve handling of invalid filenames
[wimlib] / src / win32_apply.c
index dcec1c5d558e5a181bdf701dc1b90cbc930f3846..ffee267c61bfdee2b4e8a9ae4289129e28ce23da 100644 (file)
 
 #ifdef __WIN32__
 
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
 #include <aclapi.h> /* for SetSecurityInfo() */
 
-#include "win32_common.h"
-#include "wimlib_internal.h"
-#include "dentry.h"
-#include "lookup_table.h"
-#include "endianness.h"
+#include "wimlib/win32_common.h"
+
+#include "wimlib/apply.h"
+#include "wimlib/dentry.h"
+#include "wimlib/endianness.h"
+#include "wimlib/error.h"
+#include "wimlib/lookup_table.h"
+#include "wimlib/metadata.h"
+#include "wimlib/reparse.h"
+#include "wimlib/security.h"
 
 #define MAX_CREATE_HARD_LINK_WARNINGS 5
 #define MAX_CREATE_SOFT_LINK_WARNINGS 5
@@ -48,6 +57,7 @@ L"If you are not running this program as the administrator, you may\n"
 
 static int
 win32_extract_try_rpfix(u8 *rpbuf,
+                       u16 *rpbuflen_p,
                        const wchar_t *extract_root_realpath,
                        unsigned extract_root_realpath_nchars)
 {
@@ -65,8 +75,7 @@ win32_extract_try_rpfix(u8 *rpbuf,
        size_t new_print_name_nchars;
        utf16lechar *p;
 
-       ret = parse_reparse_data(rpbuf, 8 + le16_to_cpu(*(u16*)(rpbuf + 4)),
-                                &rpdata);
+       ret = parse_reparse_data(rpbuf, *rpbuflen_p, &rpdata);
        if (ret)
                return ret;
 
@@ -88,7 +97,7 @@ win32_extract_try_rpfix(u8 *rpbuf,
        stripped_nchars = ret;
        target = rpdata.substitute_name;
        target_nchars = rpdata.substitute_name_nbytes / sizeof(utf16lechar);
-       stripped_target = target + 6;
+       stripped_target = target + stripped_nchars;
        stripped_target_nchars = target_nchars - stripped_nchars;
 
        new_target = alloca((6 + extract_root_realpath_nchars +
@@ -97,8 +106,7 @@ win32_extract_try_rpfix(u8 *rpbuf,
        p = new_target;
        if (stripped_nchars == 6) {
                /* Include \??\ prefix if it was present before */
-               wmemcpy(p, L"\\??\\", 4);
-               p += 4;
+               p = wmempcpy(p, L"\\??\\", 4);
        }
 
        /* Print name excludes the \??\ if present. */
@@ -110,12 +118,10 @@ win32_extract_try_rpfix(u8 *rpbuf,
                *p++ = extract_root_realpath[1];
        }
        /* Copy the rest of the extract root */
-       wmemcpy(p, extract_root_realpath + 2, extract_root_realpath_nchars - 2);
-       p += extract_root_realpath_nchars - 2;
+       p = wmempcpy(p, extract_root_realpath + 2, extract_root_realpath_nchars - 2);
 
        /* Append the stripped target */
-       wmemcpy(p, stripped_target, stripped_target_nchars);
-       p += stripped_target_nchars;
+       p = wmempcpy(p, stripped_target, stripped_target_nchars);
        new_target_nchars = p - new_target;
        new_print_name_nchars = p - new_print_name;
 
@@ -129,7 +135,7 @@ win32_extract_try_rpfix(u8 *rpbuf,
        rpdata.substitute_name_nbytes = new_target_nchars * sizeof(utf16lechar);
        rpdata.print_name = new_print_name;
        rpdata.print_name_nbytes = new_print_name_nchars * sizeof(utf16lechar);
-       return make_reparse_buffer(&rpdata, rpbuf);
+       return make_reparse_buffer(&rpdata, rpbuf, rpbuflen_p);
 }
 
 /* Wrapper around the FSCTL_SET_REPARSE_POINT ioctl to set the reparse data on
@@ -142,12 +148,13 @@ win32_set_reparse_data(HANDLE h,
                       struct apply_args *args)
 {
        int ret;
-       u8 rpbuf[REPARSE_POINT_MAX_SIZE];
+       u8 rpbuf[REPARSE_POINT_MAX_SIZE] _aligned_attribute(8);
        DWORD bytesReturned;
+       u16 rpbuflen;
 
        DEBUG("Setting reparse data on \"%ls\"", path);
 
-       ret = wim_inode_get_reparse_data(inode, rpbuf);
+       ret = wim_inode_get_reparse_data(inode, rpbuf, &rpbuflen);
        if (ret)
                return ret;
 
@@ -157,6 +164,7 @@ win32_set_reparse_data(HANDLE h,
            !inode->i_not_rpfixed)
        {
                ret = win32_extract_try_rpfix(rpbuf,
+                                             &rpbuflen,
                                              args->target_realpath,
                                              args->target_realpath_len);
                if (ret)
@@ -185,7 +193,7 @@ win32_set_reparse_data(HANDLE h,
         *  "Not used with this operation; set to NULL."
         */
        if (!DeviceIoControl(h, FSCTL_SET_REPARSE_POINT, rpbuf,
-                            8 + le16_to_cpu(*(u16*)(rpbuf + 4)),
+                            rpbuflen,
                             NULL, 0,
                             &bytesReturned /* lpBytesReturned */,
                             NULL /* lpOverlapped */))
@@ -668,7 +676,6 @@ win32_finish_extract_stream(HANDLE h, const struct wim_dentry *dentry,
 {
        int ret = 0;
        const struct wim_inode *inode = dentry->d_inode;
-       const wchar_t *short_name;
        if (stream_name_utf16 == NULL) {
                /* Unnamed stream. */
 
@@ -724,7 +731,7 @@ win32_finish_extract_stream(HANDLE h, const struct wim_dentry *dentry,
                }
 
                if (dentry_has_short_name(dentry))
-                       SetFileShortNameW(h, short_name);
+                       SetFileShortNameW(h, dentry->short_name);
                else if (running_on_windows_7_or_later())
                        SetFileShortNameW(h, L"");
        } else {
@@ -1089,7 +1096,7 @@ win32_check_vol_flags(const wchar_t *output_path,
        win32_get_vol_flags(output_path, &args->vol_flags);
        args->have_vol_flags = true;
 
-       missing_features = dentry_features args->vol_flags;
+       missing_features = dentry_features & ~args->vol_flags;
 
        /* Warn the user about data that may not be extracted. */
        if (missing_features & FILE_SUPPORTS_SPARSE_FILES)
@@ -1228,6 +1235,7 @@ win32_do_apply_dentry(const wchar_t *output_path,
            !(args->vol_flags & FILE_SUPPORTS_REPARSE_POINTS))
        {
                WARNING("Not extracting reparse point \"%ls\"", output_path);
+               dentry->not_extracted = 1;
        } else {
                /* Create the file, directory, or reparse point, and extract the
                 * data streams. */
@@ -1270,13 +1278,6 @@ win32_do_apply_dentry_timestamps(const wchar_t *path,
        HANDLE h;
        const struct wim_inode *inode = dentry->d_inode;
 
-       if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT &&
-           !(args->vol_flags & FILE_SUPPORTS_REPARSE_POINTS))
-       {
-               /* Skip reparse points not extracted */
-               return 0;
-       }
-
        /* Windows doesn't let you change the timestamps of the root directory
         * (at least on FAT, which is dumb but expected since FAT doesn't store
         * any metadata about the root directory...) */