From: Eric Biggers Date: Wed, 26 Nov 2014 04:26:29 +0000 (-0600) Subject: Workaround for FILE_SUPERSEDE being broken in Windows PE ramdisk X-Git-Tag: v1.7.4~44 X-Git-Url: https://wimlib.net/git/?p=wimlib;a=commitdiff_plain;h=4f8f32cfec67742301817fa6fafdbd73c0657b02 Workaround for FILE_SUPERSEDE being broken in Windows PE ramdisk --- diff --git a/NEWS b/NEWS index ba27b388..4f4d8b3f 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,8 @@ +Version 1.7.4-BETA: + Extracting files to a Windows PE in-memory filesystem no longer fails if + the target files do not yet exist. (Broken since v1.7.0, but actually a + result of a Microsoft bug.) + Version 1.7.3: Fix for very slow export from solid WIM / ESD files. diff --git a/src/win32_apply.c b/src/win32_apply.c index 9ebc161e..4b6c5c66 100644 --- a/src/win32_apply.c +++ b/src/win32_apply.c @@ -1265,6 +1265,8 @@ create_any_empty_ads(const struct wim_dentry *dentry, const struct wim_ads_entry *entry; NTSTATUS status; HANDLE h; + bool retried; + DWORD disposition; entry = &inode->i_ads_entries[i]; @@ -1285,9 +1287,23 @@ create_any_empty_ads(const struct wim_dentry *dentry, entry->stream_name_nbytes / sizeof(wchar_t)); path_modified = true; + + retried = false; + disposition = FILE_SUPERSEDE; + retry: status = do_create_file(&h, FILE_WRITE_DATA, &allocation_size, - 0, FILE_SUPERSEDE, 0, ctx); - if (!NT_SUCCESS(status)) { + 0, disposition, 0, ctx); + if (unlikely(!NT_SUCCESS(status))) { + if (status == STATUS_OBJECT_NAME_NOT_FOUND && !retried) { + /* Workaround for defect in the Windows PE + * in-memory filesystem implementation: + * FILE_SUPERSEDE does not create the file, as + * expected and documented, when the named file + * does not exist. */ + retried = true; + disposition = FILE_CREATE; + goto retry; + } set_errno_from_nt_status(status); ERROR_WITH_ERRNO("Can't create \"%ls\" " "(status=0x%08"PRIx32")", @@ -1415,6 +1431,7 @@ create_nondirectory_inode(HANDLE *h_ret, const struct wim_dentry *dentry, ULONG attrib; NTSTATUS status; bool retried = false; + DWORD disposition; inode = dentry->d_inode; @@ -1441,11 +1458,12 @@ create_nondirectory_inode(HANDLE *h_ret, const struct wim_dentry *dentry, FILE_ATTRIBUTE_ENCRYPTED)); } build_extraction_path(dentry, ctx); + disposition = FILE_SUPERSEDE; retry: status = do_create_file(h_ret, GENERIC_READ | GENERIC_WRITE | DELETE, - NULL, attrib, FILE_SUPERSEDE, + NULL, attrib, disposition, FILE_NON_DIRECTORY_FILE, ctx); - if (NT_SUCCESS(status)) { + if (likely(NT_SUCCESS(status))) { int ret; ret = adjust_compression_attribute(*h_ret, dentry, ctx); @@ -1483,6 +1501,16 @@ retry: return 0; } + if (status == STATUS_OBJECT_NAME_NOT_FOUND && !retried) { + /* Workaround for defect in the Windows PE in-memory filesystem + * implementation: FILE_SUPERSEDE does not create the file, as + * expected and documented, when the named file does not exist. + */ + retried = true; + disposition = FILE_CREATE; + goto retry; + } + if (status == STATUS_ACCESS_DENIED && !retried) { /* We also can't supersede an existing file that has * FILE_ATTRIBUTE_READONLY set; doing so causes NtCreateFile()