]> wimlib.net Git - wimlib/blobdiff - src/win32_apply.c
win32_apply.c: set_short_name(): Zero buffer
[wimlib] / src / win32_apply.c
index 89ecd21c5ea85eb400150cd57294831c353e04c6..987a4fa855004526f2aafab86e641b3151744255 100644 (file)
@@ -799,27 +799,38 @@ maybe_clear_encryption_attribute(HANDLE *h_ptr, const struct wim_dentry *dentry,
 /* Try to enable short name support on the target volume.  If successful, return
  * true.  If unsuccessful, issue a warning and return false.  */
 static bool
-try_to_enable_short_names(struct win32_apply_ctx *ctx)
+try_to_enable_short_names(const wchar_t *volume)
 {
+       HANDLE h;
        FILE_FS_PERSISTENT_VOLUME_INFORMATION info;
-       NTSTATUS status;
+       BOOL bret;
+       DWORD bytesReturned;
+
+       h = CreateFile(volume, GENERIC_WRITE,
+                      FILE_SHARE_VALID_FLAGS, NULL, OPEN_EXISTING,
+                      FILE_FLAG_BACKUP_SEMANTICS, NULL);
+       if (h == INVALID_HANDLE_VALUE)
+               goto fail;
 
        info.VolumeFlags = 0;
        info.FlagMask = PERSISTENT_VOLUME_STATE_SHORT_NAME_CREATION_DISABLED;
        info.Version = 1;
        info.Reserved = 0;
 
-       status = (*func_NtFsControlFile)(ctx->h_target, NULL, NULL, NULL,
-                                        &ctx->iosb,
-                                        FSCTL_SET_PERSISTENT_VOLUME_STATE,
-                                        &info, sizeof(info), NULL, 0);
-       if (!NT_SUCCESS(status)) {
-               WARNING("Failed to enable short name support on target volume "
-                       "(status=0x%08"PRIx32")", (u32)status);
-               return false;
-       }
+       bret = DeviceIoControl(h, FSCTL_SET_PERSISTENT_VOLUME_STATE,
+                              &info, sizeof(info), NULL, 0,
+                              &bytesReturned, NULL);
 
+       CloseHandle(h);
+
+       if (!bret)
+               goto fail;
        return true;
+
+fail:
+       WARNING("Failed to enable short name support on %ls "
+               "(err=%"PRIu32")", volume + 4, (u32)GetLastError());
+       return false;
 }
 
 /* Set the short name on the open file @h which has been created at the location
@@ -840,16 +851,30 @@ set_short_name(HANDLE h, const struct wim_dentry *dentry,
        if (!ctx->common.supported_features.short_names)
                return 0;
 
+       /*
+        * Note: The size of the FILE_NAME_INFORMATION buffer must be such that
+        * FileName contains at least 2 wide characters (4 bytes).  Otherwise,
+        * NtSetInformationFile() will return STATUS_INFO_LENGTH_MISMATCH.  This
+        * is despite the fact that FileNameLength can validly be 0 or 2 bytes,
+        * with the former case being removing the existing short name if
+        * present, rather than setting one.
+        *
+        * The null terminator is seemingly optional, but to be safe we include
+        * space for it and zero all unused space.
+        */
+
        size_t bufsize = offsetof(FILE_NAME_INFORMATION, FileName) +
-                        dentry->short_name_nbytes;
+                        max(dentry->short_name_nbytes, sizeof(wchar_t)) +
+                        sizeof(wchar_t);
        u8 buf[bufsize] _aligned_attribute(8);
        FILE_NAME_INFORMATION *info = (FILE_NAME_INFORMATION *)buf;
        NTSTATUS status;
 
+       memset(buf, 0, bufsize);
+
        info->FileNameLength = dentry->short_name_nbytes;
        memcpy(info->FileName, dentry->short_name, dentry->short_name_nbytes);
 
-
 retry:
        status = (*func_NtSetInformationFile)(h, &ctx->iosb, info, bufsize,
                                              FileShortNameInformation);
@@ -860,8 +885,16 @@ retry:
                if (dentry->short_name_nbytes == 0)
                        return 0;
                if (!ctx->tried_to_enable_short_names) {
+                       wchar_t volume[7];
+                       int ret;
+
                        ctx->tried_to_enable_short_names = true;
-                       if (try_to_enable_short_names(ctx))
+
+                       ret = win32_get_drive_path(ctx->common.target,
+                                                  volume);
+                       if (ret)
+                               return ret;
+                       if (try_to_enable_short_names(volume))
                                goto retry;
                }
        }
@@ -1073,16 +1106,15 @@ create_directories(struct list_head *dentry_list,
 
                /* If the root dentry is being extracted, it was already done so
                 * in prepare_target().  */
-               if (dentry_is_root(dentry))
-                       continue;
-
-               ret = create_directory(dentry, ctx);
-               if (ret)
-                       return ret;
+               if (!dentry_is_root(dentry)) {
+                       ret = create_directory(dentry, ctx);
+                       if (ret)
+                               return ret;
 
-               ret = create_any_empty_ads(dentry, ctx);
-               if (ret)
-                       return ret;
+                       ret = create_any_empty_ads(dentry, ctx);
+                       if (ret)
+                               return ret;
+               }
 
                ret = report_file_created(&ctx->common);
                if (ret)
@@ -1329,11 +1361,11 @@ create_nondirectories(struct list_head *dentry_list, struct win32_apply_ctx *ctx
                if (inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY)
                        continue;
                /* Call create_nondirectory() only once per inode  */
-               if (dentry != inode_first_extraction_dentry(inode))
-                       continue;
-               ret = create_nondirectory(inode, ctx);
-               if (ret)
-                       return ret;
+               if (dentry == inode_first_extraction_dentry(inode)) {
+                       ret = create_nondirectory(inode, ctx);
+                       if (ret)
+                               return ret;
+               }
                ret = report_file_created(&ctx->common);
                if (ret)
                        return ret;
@@ -2140,12 +2172,25 @@ do_warnings(const struct win32_apply_ctx *ctx)
        }
 }
 
+static uint64_t
+count_dentries(const struct list_head *dentry_list)
+{
+       const struct list_head *cur;
+       uint64_t count = 0;
+
+       list_for_each(cur, dentry_list)
+               count++;
+
+       return count;
+}
+
 /* Extract files from a WIM image to a directory on Windows  */
 static int
 win32_extract(struct list_head *dentry_list, struct apply_ctx *_ctx)
 {
        int ret;
        struct win32_apply_ctx *ctx = (struct win32_apply_ctx *)_ctx;
+       uint64_t dentry_count;
 
        ret = prepare_target(dentry_list, ctx);
        if (ret)
@@ -2157,7 +2202,11 @@ win32_extract(struct list_head *dentry_list, struct apply_ctx *_ctx)
                        goto out;
        }
 
-       reset_file_progress(&ctx->common);
+       dentry_count = count_dentries(dentry_list);
+
+       ret = start_file_structure_phase(&ctx->common, dentry_count);
+       if (ret)
+               goto out;
 
        ret = create_directories(dentry_list, ctx);
        if (ret)
@@ -2167,6 +2216,10 @@ win32_extract(struct list_head *dentry_list, struct apply_ctx *_ctx)
        if (ret)
                goto out;
 
+       ret = end_file_structure_phase(&ctx->common);
+       if (ret)
+               goto out;
+
        struct read_stream_list_callbacks cbs = {
                .begin_stream      = begin_extract_stream,
                .begin_stream_ctx  = ctx,
@@ -2179,12 +2232,18 @@ win32_extract(struct list_head *dentry_list, struct apply_ctx *_ctx)
        if (ret)
                goto out;
 
-       reset_file_progress(&ctx->common);
+       ret = start_file_metadata_phase(&ctx->common, dentry_count);
+       if (ret)
+               goto out;
 
        ret = apply_metadata(dentry_list, ctx);
        if (ret)
                goto out;
 
+       ret = end_file_metadata_phase(&ctx->common);
+       if (ret)
+               goto out;
+
        if (unlikely(ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_WIMBOOT)) {
                ret = end_wimboot_extraction(ctx);
                if (ret)