Compare commits

...

6 Commits

Author SHA1 Message Date
Alistair Leslie-Hughes
b09545bc48 Release v10.12 2025-07-12 20:06:05 +10:00
Alistair Leslie-Hughes
8c98aa0c22 Added msxml_normalize_line patchset 2025-07-12 15:22:15 +10:00
Alistair Leslie-Hughes
31cab243e7 Added comctl32_animate_avi patchset 2025-07-11 19:33:15 +10:00
Alistair Leslie-Hughes
caa47e6c73 Rebase against d1f6b3771376cc8909be712b127125e1b9e4f5d1. 2025-07-11 08:16:46 +10:00
Alistair Leslie-Hughes
d102a32693 Rebase against 177848adf54f6871e558be6b42ee2478a522c3d2. 2025-07-09 09:35:33 +10:00
Alistair Leslie-Hughes
784382204b Updated msxml3-element_props patchset
Add missing patch.
2025-07-08 15:54:55 +10:00
26 changed files with 348 additions and 1034 deletions

View File

@@ -1,4 +1,4 @@
From 8aa6fb73e3142d86ba354c204313b8a74a5fa43d Mon Sep 17 00:00:00 2001
From fb422ad56e3549e81d3b60afc77b0a0c6a56f672 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Thu, 2 Oct 2014 19:53:46 +0200
Subject: [PATCH] winelib: Append '(Staging)' at the end of the version string.
@@ -8,10 +8,10 @@ Subject: [PATCH] winelib: Append '(Staging)' at the end of the version string.
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/configure.ac b/configure.ac
index f86a5decb07..3d7f9cc96e6 100644
index b4ede761391..ea6bd2fae3c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3910,7 +3910,7 @@ dnl Rules for generated source files
@@ -3728,7 +3728,7 @@ dnl Rules for generated source files
WINE_APPEND_RULE(
[dlls/ntdll/unix/version.c: dummy
@@ -19,7 +19,7 @@ index f86a5decb07..3d7f9cc96e6 100644
+ @version=\`(GIT_DIR=${wine_srcdir}.git git describe HEAD 2>/dev/null || echo \"wine-\$(PACKAGE_VERSION)\") | sed -n -e '\$\$s/\(.*\)/const char wine_build[[]] = \"\\1 (Staging)\";/p'\` && (echo \$\$version | cmp -s - \$[@]) || echo \$\$version >\$[@] || (rm -f \$[@] && exit 1)
programs/winetest/build.rc: dummy
@build=\"STRINGTABLE { 1 \\\"\`GIT_DIR=${wine_srcdir}.git git rev-parse HEAD 2>/dev/null\`\\\" }\" && (echo \$\$build | cmp -s - \$[@]) || echo \$\$build >\$[@] || (rm -f \$[@] && exit 1)
programs/winetest/build.nfo:
dlls/wineandroid.drv/wine-debug.apk: dlls/wineandroid.drv/build.gradle ${wine_srcdir}dlls/wineandroid.drv/AndroidManifest.xml ${wine_srcdir}dlls/wineandroid.drv/WineActivity.java ${wine_srcdir}dlls/wineandroid.drv/wine.svg
--
2.33.0
2.47.2

View File

@@ -0,0 +1,24 @@
From 8a9c55d23750ca2650eba518e46549d8b5d94b43 Mon Sep 17 00:00:00 2001
From: Alistair Leslie-Hughes <leslie_alistair@hotmail.com>
Date: Fri, 11 Jul 2025 14:11:36 +1000
Subject: [PATCH] comctl32: Animate support AVI msvc codex
---
dlls/comctl32/animate.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/dlls/comctl32/animate.c b/dlls/comctl32/animate.c
index 46e1e37b72d..717422c784f 100644
--- a/dlls/comctl32/animate.c
+++ b/dlls/comctl32/animate.c
@@ -644,6 +644,7 @@ static BOOL ANIMATE_GetAviCodec(ANIMATE_INFO *infoPtr)
/* check uncompressed AVI */
if ((infoPtr->ash.fccHandler == mmioFOURCC('D', 'I', 'B', ' ')) ||
(infoPtr->ash.fccHandler == mmioFOURCC('R', 'L', 'E', ' ')) ||
+ (infoPtr->ash.fccHandler == mmioFOURCC('m', 's', 'v', 'c')) ||
(infoPtr->ash.fccHandler == mmioFOURCC(0, 0, 0, 0)))
{
infoPtr->hic = 0;
--
2.47.2

View File

@@ -0,0 +1,24 @@
From b8cce6663a956f8fb8f07700672e378b44b1af1c Mon Sep 17 00:00:00 2001
From: Alistair Leslie-Hughes <leslie_alistair@hotmail.com>
Date: Fri, 11 Jul 2025 15:21:07 +1000
Subject: [PATCH] comctl32: Animate to support RLE8 codex
---
dlls/comctl32/animate.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/dlls/comctl32/animate.c b/dlls/comctl32/animate.c
index 717422c784f..ca4fae85a11 100644
--- a/dlls/comctl32/animate.c
+++ b/dlls/comctl32/animate.c
@@ -645,6 +645,7 @@ static BOOL ANIMATE_GetAviCodec(ANIMATE_INFO *infoPtr)
if ((infoPtr->ash.fccHandler == mmioFOURCC('D', 'I', 'B', ' ')) ||
(infoPtr->ash.fccHandler == mmioFOURCC('R', 'L', 'E', ' ')) ||
(infoPtr->ash.fccHandler == mmioFOURCC('m', 's', 'v', 'c')) ||
+ (infoPtr->ash.fccHandler == mmioFOURCC('m', 'r', 'l', 'e')) ||
(infoPtr->ash.fccHandler == mmioFOURCC(0, 0, 0, 0)))
{
infoPtr->hic = 0;
--
2.47.2

View File

@@ -0,0 +1,119 @@
From 2ef9715ae9fffa0a6d7cdf0dc04e8de7eb245ce4 Mon Sep 17 00:00:00 2001
From: Alistair Leslie-Hughes <leslie_alistair@hotmail.com>
Date: Fri, 11 Jul 2025 18:07:39 +1000
Subject: [PATCH] comctl32: Animate control doesn't support compressed AVI
The Animate control only supporst uncompress AVI with the excpetion of RLE8.
---
dlls/comctl32/animate.c | 64 ++---------------------------------------
1 file changed, 3 insertions(+), 61 deletions(-)
diff --git a/dlls/comctl32/animate.c b/dlls/comctl32/animate.c
index ca4fae85a11..74516db81f5 100644
--- a/dlls/comctl32/animate.c
+++ b/dlls/comctl32/animate.c
@@ -39,14 +39,6 @@
WINE_DEFAULT_DEBUG_CHANNEL(animate);
-static struct {
- HMODULE hModule;
- HIC (WINAPI *fnICOpen)(DWORD, DWORD, UINT);
- LRESULT (WINAPI *fnICClose)(HIC);
- LRESULT (WINAPI *fnICSendMessage)(HIC, UINT, DWORD_PTR, DWORD_PTR);
- DWORD (WINAPIV *fnICDecompress)(HIC,DWORD,LPBITMAPINFOHEADER,LPVOID,LPBITMAPINFOHEADER,LPVOID);
-} fnIC;
-
typedef struct
{
/* reference to input stream (file or resource) */
@@ -189,11 +181,6 @@ static void ANIMATE_Free(ANIMATE_INFO *infoPtr)
}
Free (infoPtr->lpIndex);
infoPtr->lpIndex = NULL;
- if (infoPtr->hic)
- {
- fnIC.fnICClose(infoPtr->hic);
- infoPtr->hic = 0;
- }
Free (infoPtr->inbih);
infoPtr->inbih = NULL;
Free (infoPtr->outbih);
@@ -342,13 +329,6 @@ static BOOL ANIMATE_DrawFrame(ANIMATE_INFO *infoPtr, HDC hDC)
mmioSeek(infoPtr->hMMio, infoPtr->lpIndex[infoPtr->currFrame], SEEK_SET);
mmioRead(infoPtr->hMMio, infoPtr->indata, infoPtr->ash.dwSuggestedBufferSize);
- if (infoPtr->hic &&
- fnIC.fnICDecompress(infoPtr->hic, 0, infoPtr->inbih, infoPtr->indata,
- infoPtr->outbih, infoPtr->outdata) != ICERR_OK) {
- WARN("Decompression error\n");
- return FALSE;
- }
-
ANIMATE_PaintFrame(infoPtr, hDC);
if (infoPtr->currFrame++ >= infoPtr->nToFrame) {
@@ -649,39 +629,12 @@ static BOOL ANIMATE_GetAviCodec(ANIMATE_INFO *infoPtr)
(infoPtr->ash.fccHandler == mmioFOURCC(0, 0, 0, 0)))
{
infoPtr->hic = 0;
- return TRUE;
- }
-
- /* try to get a decompressor for that type */
- infoPtr->hic = fnIC.fnICOpen(ICTYPE_VIDEO, infoPtr->ash.fccHandler, ICMODE_DECOMPRESS);
- if (!infoPtr->hic) {
- WARN("Can't load codec for the file\n");
- return FALSE;
- }
-
- outSize = fnIC.fnICSendMessage(infoPtr->hic, ICM_DECOMPRESS_GET_FORMAT,
- (DWORD_PTR)infoPtr->inbih, 0L);
-
- if (!(infoPtr->outbih = Alloc(outSize)))
- return FALSE;
-
- if (fnIC.fnICSendMessage(infoPtr->hic, ICM_DECOMPRESS_GET_FORMAT,
- (DWORD_PTR)infoPtr->inbih, (DWORD_PTR)infoPtr->outbih) != ICERR_OK)
- {
- WARN("Can't get output BIH\n");
- return FALSE;
+ return TRUE;
}
- if (!(infoPtr->outdata = Alloc(infoPtr->outbih->biSizeImage)))
- return FALSE;
+ FIXME("Unsupported %s\n", debugstr_fourcc(infoPtr->ash.fccHandler));
- if (fnIC.fnICSendMessage(infoPtr->hic, ICM_DECOMPRESS_BEGIN,
- (DWORD_PTR)infoPtr->inbih, (DWORD_PTR)infoPtr->outbih) != ICERR_OK) {
- WARN("Can't begin decompression\n");
- return FALSE;
- }
-
- return TRUE;
+ return FALSE;
}
@@ -790,17 +743,6 @@ static BOOL ANIMATE_Create(HWND hWnd, const CREATESTRUCTW *lpcs)
{
ANIMATE_INFO *infoPtr;
- if (!fnIC.hModule)
- {
- fnIC.hModule = LoadLibraryW(L"msvfw32.dll");
- if (!fnIC.hModule) return FALSE;
-
- fnIC.fnICOpen = (void*)GetProcAddress(fnIC.hModule, "ICOpen");
- fnIC.fnICClose = (void*)GetProcAddress(fnIC.hModule, "ICClose");
- fnIC.fnICSendMessage = (void*)GetProcAddress(fnIC.hModule, "ICSendMessage");
- fnIC.fnICDecompress = (void*)GetProcAddress(fnIC.hModule, "ICDecompress");
- }
-
/* allocate memory for info structure */
infoPtr = Alloc(sizeof(*infoPtr));
if (!infoPtr) return FALSE;
--
2.47.2

View File

@@ -0,0 +1,2 @@
Fixes: [52278] comctl32: Animate support AVI msvc codex.

View File

@@ -0,0 +1,97 @@
From 2135156d666a6a7a779326b7f1fdcbd2a8d58c8a Mon Sep 17 00:00:00 2001
From: Spencer Wallace <spencerwallace@esri.com>
Date: Mon, 24 Feb 2025 13:33:18 -0800
Subject: [PATCH] msxml3: Correct looping of Document Element properties.
---
dlls/msxml3/element.c | 2 ++
dlls/msxml3/tests/domdoc.c | 53 ++++++++++++++++++++++++++++++++++++++
2 files changed, 55 insertions(+)
diff --git a/dlls/msxml3/element.c b/dlls/msxml3/element.c
index 0fe72dcef9c..3e3c2d06169 100644
--- a/dlls/msxml3/element.c
+++ b/dlls/msxml3/element.c
@@ -1812,6 +1812,8 @@ static HRESULT domelem_get_item(const xmlNodePtr node, LONG index, IXMLDOMNode *
*item = create_node( (xmlNodePtr) curr );
return S_OK;
}
+
+ ++attrIndex;
}
if (!node->nsDef)
diff --git a/dlls/msxml3/tests/domdoc.c b/dlls/msxml3/tests/domdoc.c
index dcb83f781ba..84a1f330582 100644
--- a/dlls/msxml3/tests/domdoc.c
+++ b/dlls/msxml3/tests/domdoc.c
@@ -10224,6 +10224,15 @@ static void test_get_attributes(void)
L"xmlns:dcterms",
L"xmlns:foaf"
};
+ const WCHAR *attributes[] =
+ {
+ L"rdf:about",
+ L"dcterms:created",
+ L"xmlns:oslc_am",
+ L"xmlns:rdf",
+ L"xmlns:dcterms",
+ L"xmlns:foaf"
+ };
const get_attributes_t *entry = get_attributes;
IXMLDOMNamedNodeMap *map;
IXMLDOMDocument *doc, *doc2;
@@ -10505,6 +10514,50 @@ static void test_get_attributes(void)
IXMLDOMDocument_Release(doc);
+ str = SysAllocString(L"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+ L"<rdf:RDF rdf:about=\"foo\""
+ L" dcterms:created=\"2025\""
+ L" xmlns:oslc_am=\"http://open-services.net/ns/am#\""
+ L" xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\""
+ L" xmlns:dcterms=\"http://purl.org/dc/terms/\""
+ L" xmlns:foaf=\"http://xmlns.com/foaf/0.1/\" >"
+ L"</rdf:RDF>");
+
+ doc = create_document(&IID_IXMLDOMDocument2);
+
+ hr = IXMLDOMDocument_loadXML(doc, str, &b);
+ ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(b == VARIANT_TRUE, "got %d\n", b);
+
+ hr = IXMLDOMDocument_get_documentElement(doc, &elem);
+ ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+ hr = IXMLDOMElement_get_attributes(elem, &map);
+ ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+ length = -1;
+ hr = IXMLDOMNamedNodeMap_get_length(map, &length);
+ ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(length == 6, "length %#lx.\n", length);
+
+ for(i=0; i < length; i++)
+ {
+ hr = IXMLDOMNamedNodeMap_get_item(map, i, &node2);
+ ok( hr == S_OK, "Unexpected hr %#lx (%ld).\n", hr, i);
+
+ hr = IXMLDOMNode_get_nodeName(node2, &str);
+ ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(!lstrcmpW(str, attributes[i]), "got %s\n", wine_dbgstr_w(str));
+ SysFreeString(str);
+
+ IXMLDOMNode_Release(node2);
+ }
+
+ IXMLDOMNamedNodeMap_Release(map);
+ IXMLDOMElement_Release(elem);
+
+ IXMLDOMDocument_Release(doc);
+
free_bstrs();
}
--
2.47.2

View File

@@ -0,0 +1,46 @@
From 9be306cd143e6bf5f300a321101fb713edb9155b Mon Sep 17 00:00:00 2001
From: Alistair Leslie-Hughes <leslie_alistair@hotmail.com>
Date: Sat, 12 Jul 2025 15:20:04 +1000
Subject: [PATCH] msxml: Support ISAXXMLReader::putFeature
normalize-line-breaks option
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=36686
---
dlls/msxml3/saxreader.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/dlls/msxml3/saxreader.c b/dlls/msxml3/saxreader.c
index 71a7f334420..9650af38597 100644
--- a/dlls/msxml3/saxreader.c
+++ b/dlls/msxml3/saxreader.c
@@ -60,7 +60,8 @@ typedef enum
SuppressValidationfatalError = 1 << 12,
UseInlineSchema = 1 << 13,
UseSchemaLocation = 1 << 14,
- LexicalHandlerParEntities = 1 << 15
+ LexicalHandlerParEntities = 1 << 15,
+ NormalizeLineBreaks = 1 << 16,
} saxreader_feature;
struct saxreader_feature_pair
@@ -78,6 +79,7 @@ static const struct saxreader_feature_pair saxreader_feature_map[] = {
{ Namespaces, L"http://xml.org/sax/features/namespaces" },
{ ProhibitDTD, L"prohibit-dtd" },
{ SchemaValidation, L"schema-validation" },
+ { NormalizeLineBreaks, L"normalize-line-breaks" },
};
static saxreader_feature get_saxreader_feature(const WCHAR *name)
@@ -3159,7 +3161,8 @@ static HRESULT WINAPI isaxxmlreader_putFeature(
if (feature == LexicalHandlerParEntities ||
feature == ProhibitDTD ||
feature == ExternalGeneralEntities ||
- feature == ExternalParameterEntities)
+ feature == ExternalParameterEntities ||
+ feature == NormalizeLineBreaks)
{
FIXME("(%p)->(%s %x) stub\n", This, debugstr_w(feature_name), value);
return set_feature_value(This, feature, value);
--
2.47.2

View File

@@ -0,0 +1,2 @@
Fixes: [36686] msxml: Support ISAXXMLReader::putFeature normalize-line-breaks option

View File

@@ -38,190 +38,6 @@ index f7558bb5d86..aad14d17e61 100644
EXTRADLLFLAGS = -nodefaultlibs
i386_EXTRADLLFLAGS = -Wl,--image-base,0x7bc00000
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index a2ccf3f5332..121ebe5d62a 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -38,6 +38,7 @@
#include "winuser.h"
#include "winioctl.h"
#include "winnls.h"
+#include "ddk/ntifs.h"
#ifndef IO_COMPLETION_ALL_ACCESS
#define IO_COMPLETION_ALL_ACCESS 0x001F0003
@@ -5970,32 +5971,154 @@ static void test_mailslot_name(void)
CloseHandle( device );
}
+static INT build_reparse_buffer(const WCHAR *filename, REPARSE_DATA_BUFFER **pbuffer)
+{
+ static INT header_size = offsetof(REPARSE_DATA_BUFFER, GenericReparseBuffer);
+ INT buffer_size, struct_size, data_size, string_len, prefix_len;
+ WCHAR *subst_dest, *print_dest;
+ REPARSE_DATA_BUFFER *buffer;
+
+ struct_size = offsetof(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer[0]);
+ prefix_len = strlen("\\??\\");
+ string_len = lstrlenW(&filename[prefix_len]);
+ data_size = (prefix_len + 2 * string_len + 2) * sizeof(WCHAR);
+ buffer_size = struct_size + data_size;
+ buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buffer_size);
+ buffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
+ buffer->ReparseDataLength = struct_size - header_size + data_size;
+ buffer->MountPointReparseBuffer.SubstituteNameLength = (prefix_len + string_len) * sizeof(WCHAR);
+ buffer->MountPointReparseBuffer.PrintNameOffset = (prefix_len + string_len + 1) * sizeof(WCHAR);
+ buffer->MountPointReparseBuffer.PrintNameLength = string_len * sizeof(WCHAR);
+ subst_dest = &buffer->MountPointReparseBuffer.PathBuffer[0];
+ print_dest = &buffer->MountPointReparseBuffer.PathBuffer[prefix_len + string_len + 1];
+ lstrcpyW(subst_dest, filename);
+ lstrcpyW(print_dest, &filename[prefix_len]);
+ *pbuffer = buffer;
+ return buffer_size;
+}
+
static void test_reparse_points(void)
{
- OBJECT_ATTRIBUTES attr;
- HANDLE handle;
- IO_STATUS_BLOCK io;
- NTSTATUS status;
+ WCHAR path[MAX_PATH], reparse_path[MAX_PATH], target_path[MAX_PATH], volnameW[MAX_PATH];
+ static const WCHAR reparseW[] = {'\\','r','e','p','a','r','s','e',0};
+ static const WCHAR targetW[] = {'\\','t','a','r','g','e','t',0};
+ static const WCHAR parentW[] = {'\\','.','.','\\',0};
+ static const WCHAR fooW[] = {'f','o','o',0};
+ static WCHAR volW[] = {'c',':','\\',0};
+ static const WCHAR dotW[] = {'.',0};
+ REPARSE_DATA_BUFFER *buffer = NULL;
+ DWORD dwret, dwLen, dwFlags;
UNICODE_STRING nameW;
- unsigned char reparse_data[1];
+ WCHAR *long_path;
+ INT buffer_len;
+ HANDLE handle;
+ BOOL bret;
+
+ /* Create a temporary folder for the junction point tests */
+ GetTempFileNameW(dotW, fooW, 0, path);
+ DeleteFileW(path);
+ if (!CreateDirectoryW(path, NULL))
+ {
+ win_skip("Unable to create a temporary junction point directory.\n");
+ return;
+ }
+
+ /* Check that the volume this folder is located on supports junction points */
+ pRtlDosPathNameToNtPathName_U(path, &nameW, NULL, NULL);
+ volW[0] = nameW.Buffer[4];
+ pRtlFreeUnicodeString( &nameW );
+ if (!GetVolumeNameForVolumeMountPointW(volW, volnameW, MAX_PATH))
+ {
+ win_skip("Failed to obtain volume name for current volume.\n");
+ return;
+ }
+ GetVolumeInformationW(volnameW, 0, 0, 0, &dwLen, &dwFlags, 0, 0);
+ if (!(dwFlags & FILE_SUPPORTS_REPARSE_POINTS))
+ {
+ skip("File system does not support reparse points.\n");
+ RemoveDirectoryW(path);
+ return;
+ }
- pRtlInitUnicodeString( &nameW, L"\\??\\C:\\" );
- InitializeObjectAttributes( &attr, &nameW, 0, NULL, NULL );
+ /* Create the folder to be replaced by a junction point */
+ lstrcpyW(reparse_path, path);
+ lstrcatW(reparse_path, reparseW);
+ bret = CreateDirectoryW(reparse_path, NULL);
+ ok(bret, "Failed to create junction point directory.\n");
- status = pNtOpenFile( &handle, READ_CONTROL, &attr, &io, 0, 0 );
- ok( !status, "open %s failed %#lx\n", wine_dbgstr_w(nameW.Buffer), status );
+ /* Create a destination folder for the junction point to target */
+ lstrcpyW(target_path, path);
+ for (int i=0; i<1; i++)
+ {
+ lstrcatW(target_path, parentW);
+ lstrcatW(target_path, path);
+ }
+ lstrcatW(target_path, targetW);
+ bret = CreateDirectoryW(target_path, NULL);
+ ok(bret, "Failed to create junction point target directory.\n");
+ pRtlDosPathNameToNtPathName_U(path, &nameW, NULL, NULL);
- status = pNtFsControlFile( handle, NULL, NULL, NULL, &io, FSCTL_GET_REPARSE_POINT, NULL, 0, NULL, 0 );
- ok( status == STATUS_INVALID_USER_BUFFER, "expected %#lx, got %#lx\n", STATUS_INVALID_USER_BUFFER, status );
+ /* construct a too long pathname (resulting reparse buffer over 16 kiB limit) */
+ long_path = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 32767);
+ lstrcpyW(long_path, nameW.Buffer);
+ for (int i=0; i<250; i++)
+ {
+ lstrcatW(long_path, parentW);
+ lstrcatW(long_path, path);
+ }
+ lstrcatW(long_path, targetW);
- status = pNtFsControlFile( handle, NULL, NULL, NULL, &io, FSCTL_GET_REPARSE_POINT, NULL, 0, reparse_data, 0 );
- ok( status == STATUS_INVALID_USER_BUFFER, "expected %#lx, got %#lx\n", STATUS_INVALID_USER_BUFFER, status );
+ /* Create the junction point */
+ handle = CreateFileW(reparse_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0);
+ if (handle == INVALID_HANDLE_VALUE)
+ {
+ win_skip("Failed to open junction point directory handle (0x%lx).\n", GetLastError());
+ goto cleanup;
+ }
+ buffer_len = build_reparse_buffer(long_path, &buffer);
+ bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
+ ok(!bret && GetLastError()==ERROR_INVALID_REPARSE_DATA, "Unexpected error (0x%lx)\n", GetLastError());
+ HeapFree(GetProcessHeap(), 0, buffer);
+ CloseHandle(handle);
- /* a volume cannot be a reparse point by definition */
- status = pNtFsControlFile( handle, NULL, NULL, NULL, &io, FSCTL_GET_REPARSE_POINT, NULL, 0, reparse_data, 1 );
- ok( status == STATUS_NOT_A_REPARSE_POINT, "expected %#lx, got %#lx\n", STATUS_NOT_A_REPARSE_POINT, status );
+ /* construct a long pathname to demonstrate correct behavior with very large reparse points */
+ pRtlDosPathNameToNtPathName_U(path, &nameW, NULL, NULL);
+ lstrcpyW(long_path, nameW.Buffer);
+ for (int i=0; i<200; i++)
+ {
+ lstrcatW(long_path, parentW);
+ lstrcatW(long_path, path);
+ }
+ lstrcatW(long_path, targetW);
- CloseHandle( handle );
+ /* use a sane (not obscenely long) target for the rest of testing */
+ pRtlFreeUnicodeString(&nameW);
+ pRtlDosPathNameToNtPathName_U(target_path, &nameW, NULL, NULL);
+
+ /* Create the junction point */
+ handle = CreateFileW(reparse_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0);
+ if (handle == INVALID_HANDLE_VALUE)
+ {
+ win_skip("Failed to open junction point directory handle (0x%lx).\n", GetLastError());
+ goto cleanup;
+ }
+ buffer_len = build_reparse_buffer(long_path, &buffer);
+ bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
+ ok(bret, "Failed to create junction point! (0x%lx)\n", GetLastError());
+ CloseHandle(handle);
+
+cleanup:
+ /* Cleanup */
+ pRtlFreeUnicodeString(&nameW);
+ HeapFree(GetProcessHeap(), 0, long_path);
+ HeapFree(GetProcessHeap(), 0, buffer);
+ bret = RemoveDirectoryW(reparse_path);
+ todo_wine ok(bret, "Failed to remove temporary reparse point directory!\n");
+ bret = RemoveDirectoryW(target_path);
+ ok(bret, "Failed to remove temporary target directory!\n");
+ RemoveDirectoryW(path);
}
static void test_set_io_completion_ex(void)
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index 8d2809ca193..672a1d1fa27 100644
--- a/dlls/ntdll/unix/file.c

View File

@@ -5,55 +5,9 @@ Subject: [PATCH] ntdll: Add support for reading reparse points.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/ntdll/tests/file.c | 21 +++-
dlls/ntdll/unix/file.c | 221 ++++++++++++++++++++++++++++++++++++++--
2 files changed, 231 insertions(+), 11 deletions(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index 148b6058cee..441bb69adcb 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -5896,14 +5896,14 @@ static void test_reparse_points(void)
static const WCHAR reparseW[] = {'\\','r','e','p','a','r','s','e',0};
static const WCHAR targetW[] = {'\\','t','a','r','g','e','t',0};
static const WCHAR parentW[] = {'\\','.','.','\\',0};
+ INT buffer_len, string_len, path_len, total_len;
static const WCHAR fooW[] = {'f','o','o',0};
static WCHAR volW[] = {'c',':','\\',0};
static const WCHAR dotW[] = {'.',0};
REPARSE_DATA_BUFFER *buffer = NULL;
DWORD dwret, dwLen, dwFlags;
+ WCHAR *dest, *long_path;
UNICODE_STRING nameW;
- WCHAR *long_path;
- INT buffer_len;
HANDLE handle;
BOOL bret;
@@ -6000,6 +6000,23 @@ static void test_reparse_points(void)
buffer_len = build_reparse_buffer(long_path, &buffer);
bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
ok(bret, "Failed to create junction point! (0x%lx)\n", GetLastError());
+
+ /* Read back the junction point */
+ HeapFree(GetProcessHeap(), 0, buffer);
+ buffer_len = sizeof(*buffer) + 2*32767;
+ buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buffer_len);
+ bret = DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, NULL, 0, (LPVOID)buffer, buffer_len, &dwret, 0);
+ ok(bret, "Failed to read junction point! (last error=0x%lx)\n", GetLastError());
+ string_len = buffer->MountPointReparseBuffer.SubstituteNameLength;
+ dest = &buffer->MountPointReparseBuffer.PathBuffer[buffer->MountPointReparseBuffer.SubstituteNameOffset/sizeof(WCHAR)];
+ ok((memcmp(dest, long_path, string_len) == 0), "Junction point destination does not match ('%s' != '%s')!\n",
+ wine_dbgstr_w(dest), wine_dbgstr_w(long_path));
+ path_len = buffer->MountPointReparseBuffer.PrintNameOffset/sizeof(WCHAR);
+ path_len += buffer->MountPointReparseBuffer.PrintNameLength/sizeof(WCHAR);
+ total_len = FIELD_OFFSET(typeof(*buffer), MountPointReparseBuffer.PathBuffer[path_len+1])
+ - FIELD_OFFSET(typeof(*buffer), GenericReparseBuffer);
+ ok(buffer->ReparseDataLength == total_len, "ReparseDataLength has unexpected value (%d != %d)\n",
+ buffer->ReparseDataLength, total_len);
CloseHandle(handle);
cleanup:
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index 0d58abbfa84..3e160fb1e5c 100644
--- a/dlls/ntdll/unix/file.c

View File

@@ -5,71 +5,9 @@ Subject: [PATCH] ntdll: Add support for deleting reparse points.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/ntdll/tests/file.c | 23 +++++++++-
dlls/ntdll/unix/file.c | 99 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 121 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index b9ec79e37e0..f90509d62a1 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -5388,12 +5388,15 @@ static void test_reparse_points(void)
static const WCHAR targetW[] = {'\\','t','a','r','g','e','t',0};
static const WCHAR parentW[] = {'\\','.','.','\\',0};
INT buffer_len, string_len, path_len, total_len;
+ FILE_BASIC_INFORMATION old_attrib, new_attrib;
static const WCHAR fooW[] = {'f','o','o',0};
static WCHAR volW[] = {'c',':','\\',0};
+ REPARSE_GUID_DATA_BUFFER guid_buffer;
static const WCHAR dotW[] = {'.',0};
REPARSE_DATA_BUFFER *buffer = NULL;
DWORD dwret, dwLen, dwFlags;
WCHAR *dest, *long_path;
+ IO_STATUS_BLOCK iosb;
UNICODE_STRING nameW;
HANDLE handle;
BOOL bret;
@@ -5488,6 +5491,8 @@ static void test_reparse_points(void)
win_skip("Failed to open junction point directory handle (0x%lx).\n", GetLastError());
goto cleanup;
}
+ dwret = NtQueryInformationFile(handle, &iosb, &old_attrib, sizeof(old_attrib), FileBasicInformation);
+ ok(dwret == STATUS_SUCCESS, "Failed to get junction point folder's attributes (0x%lx).\n", dwret);
buffer_len = build_reparse_buffer(long_path, &buffer);
bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
ok(bret, "Failed to create junction point! (0x%lx)\n", GetLastError());
@@ -5508,6 +5513,22 @@ static void test_reparse_points(void)
- FIELD_OFFSET(typeof(*buffer), GenericReparseBuffer);
ok(buffer->ReparseDataLength == total_len, "ReparseDataLength has unexpected value (%d != %d)\n",
buffer->ReparseDataLength, total_len);
+
+ /* Delete the junction point */
+ memset(&old_attrib, 0x00, sizeof(old_attrib));
+ old_attrib.LastAccessTime.QuadPart = 0x200deadcafebeef;
+ dwret = NtSetInformationFile(handle, &iosb, &old_attrib, sizeof(old_attrib), FileBasicInformation);
+ ok(dwret == STATUS_SUCCESS, "Failed to set junction point folder's attributes (0x%lx).\n", dwret);
+ memset(&guid_buffer, 0x00, sizeof(guid_buffer));
+ guid_buffer.ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
+ bret = DeviceIoControl(handle, FSCTL_DELETE_REPARSE_POINT, (LPVOID)&guid_buffer,
+ REPARSE_GUID_DATA_BUFFER_HEADER_SIZE, NULL, 0, &dwret, 0);
+ ok(bret, "Failed to delete junction point! (0x%lx)\n", GetLastError());
+ memset(&new_attrib, 0x00, sizeof(new_attrib));
+ dwret = NtQueryInformationFile(handle, &iosb, &new_attrib, sizeof(new_attrib), FileBasicInformation);
+ ok(dwret == STATUS_SUCCESS, "Failed to get junction point folder's attributes (0x%lx).\n", dwret);
+ ok(old_attrib.LastAccessTime.QuadPart == new_attrib.LastAccessTime.QuadPart,
+ "Junction point folder's access time does not match.\n");
CloseHandle(handle);
cleanup:
@@ -5516,7 +5537,7 @@ cleanup:
HeapFree(GetProcessHeap(), 0, long_path);
HeapFree(GetProcessHeap(), 0, buffer);
bret = RemoveDirectoryW(reparse_path);
- todo_wine ok(bret, "Failed to remove temporary reparse point directory!\n");
+ ok(bret, "Failed to remove temporary reparse point directory!\n");
bret = RemoveDirectoryW(target_path);
ok(bret, "Failed to remove temporary target directory!\n");
RemoveDirectoryW(path);
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index 92ce83b685e..ba77aab61b7 100644
--- a/dlls/ntdll/unix/file.c

View File

@@ -6,26 +6,9 @@ Subject: ntdll: Add support for testing for reparse points with
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/ntdll/tests/file.c | 5 +++++
dlls/ntdll/unix/file.c | 23 +++++++++++++++++++----
2 files changed, 24 insertions(+), 4 deletions(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index a127a2f4f88..ffc4ca44e32 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -5469,6 +5469,11 @@ static void test_reparse_points(void)
bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
ok(bret, "Failed to create junction point! (0x%lx)\n", GetLastError());
+ /* Check the file attributes of the junction point */
+ dwret = GetFileAttributesW(reparse_path);
+ ok(dwret != (DWORD)~0, "Reparse point doesn't exist (attributes: 0x%lx)!\n", dwret);
+ ok(dwret & FILE_ATTRIBUTE_REPARSE_POINT, "File is not a reparse point! (attributes: 0x%lx)\n", dwret);
+
/* Read back the junction point */
HeapFree(GetProcessHeap(), 0, buffer);
buffer_len = sizeof(*buffer) + 2*32767;
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index 4c221f53bfd..948074b35ec 100644
--- a/dlls/ntdll/unix/file.c

View File

@@ -7,7 +7,6 @@ Subject: kernelbase: Add support for deleting reparse points with
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/kernelbase/file.c | 2 +-
dlls/ntdll/tests/file.c | 28 +++++++++++++++++++++++++++-
2 files changed, 28 insertions(+), 2 deletions(-)
diff --git a/dlls/kernelbase/file.c b/dlls/kernelbase/file.c
@@ -23,63 +22,6 @@ index bfb291fa925..6214f549406 100644
RtlFreeUnicodeString( &nt_name );
if (!status)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index ffc4ca44e32..f3aad01ee93 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -5363,11 +5363,11 @@ static void test_reparse_points(void)
FILE_BASIC_INFORMATION old_attrib, new_attrib;
static const WCHAR fooW[] = {'f','o','o',0};
static WCHAR volW[] = {'c',':','\\',0};
+ WCHAR *dest, *long_path, *abs_target;
REPARSE_GUID_DATA_BUFFER guid_buffer;
static const WCHAR dotW[] = {'.',0};
REPARSE_DATA_BUFFER *buffer = NULL;
DWORD dwret, dwLen, dwFlags;
- WCHAR *dest, *long_path;
IO_STATUS_BLOCK iosb;
UNICODE_STRING nameW;
HANDLE handle;
@@ -5454,6 +5454,7 @@ static void test_reparse_points(void)
/* use a sane (not obscenely long) target for the rest of testing */
pRtlFreeUnicodeString(&nameW);
pRtlDosPathNameToNtPathName_U(target_path, &nameW, NULL, NULL);
+ abs_target = nameW.Buffer;
/* Create the junction point */
handle = CreateFileW(reparse_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
@@ -5508,6 +5509,31 @@ static void test_reparse_points(void)
"Junction point folder's access time does not match.\n");
CloseHandle(handle);
+ /* Check deleting a junction point as if it were a directory */
+ HeapFree(GetProcessHeap(), 0, buffer);
+ handle = CreateFileW(reparse_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0);
+ buffer_len = build_reparse_buffer(abs_target, &buffer);
+ bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
+ ok(bret, "Failed to create junction point! (0x%lx)\n", GetLastError());
+ CloseHandle(handle);
+ bret = RemoveDirectoryW(reparse_path);
+ ok(bret, "Failed to delete junction point as directory!\n");
+ dwret = GetFileAttributesW(reparse_path);
+ ok(dwret == (DWORD)~0, "Junction point still exists (attributes: 0x%lx)!\n", dwret);
+
+ /* Check deleting a junction point as if it were a file */
+ HeapFree(GetProcessHeap(), 0, buffer);
+ bret = CreateDirectoryW(reparse_path, NULL);
+ ok(bret, "Failed to create junction point target directory.\n");
+ handle = CreateFileW(reparse_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0);
+ buffer_len = build_reparse_buffer(abs_target, &buffer);
+ bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
+ ok(bret, "Failed to create junction point! (0x%lx)\n", GetLastError());
+ CloseHandle(handle);
+ /* TODO: use DeleteFile on reparse point */
+
cleanup:
/* Cleanup */
pRtlFreeUnicodeString(&nameW);
--
2.17.1

View File

@@ -7,7 +7,6 @@ Subject: [PATCH] kernelbase: Add support for deleting reparse points with
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/kernelbase/file.c | 3 ++-
dlls/ntdll/tests/file.c | 11 +++++++++--
2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/dlls/kernelbase/file.c b/dlls/kernelbase/file.c
@@ -24,35 +23,6 @@ index 36b43d345d6..b7d16410d75 100644
if (status == STATUS_SUCCESS) status = NtClose(hFile);
RtlFreeUnicodeString( &nameW );
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index d4833d84906..598fdc77830 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -6007,7 +6007,7 @@ static void test_reparse_points(void)
REPARSE_GUID_DATA_BUFFER guid_buffer;
static const WCHAR dotW[] = {'.',0};
REPARSE_DATA_BUFFER *buffer = NULL;
- DWORD dwret, dwLen, dwFlags;
+ DWORD dwret, dwLen, dwFlags, err;
IO_STATUS_BLOCK iosb;
UNICODE_STRING nameW;
HANDLE handle;
@@ -6172,7 +6172,14 @@ static void test_reparse_points(void)
bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
ok(bret, "Failed to create junction point! (0x%lx)\n", GetLastError());
CloseHandle(handle);
- /* TODO: use DeleteFile on reparse point */
+ bret = DeleteFileW(reparse_path);
+ ok(!bret, "Succeeded in deleting junction point as file!\n");
+ err = GetLastError();
+ ok(err == ERROR_ACCESS_DENIED, "Expected last error 0x%x for DeleteFile on junction point (actually 0x%lx)!\n",
+ ERROR_ACCESS_DENIED, err);
+ dwret = GetFileAttributesW(reparse_path);
+ ok(dwret != (DWORD)~0, "Junction point doesn't exist (attributes: 0x%lx)!\n", dwret);
+ ok(dwret & FILE_ATTRIBUTE_REPARSE_POINT, "File is not a junction point! (attributes: 0x%lx)\n", dwret);
cleanup:
/* Cleanup */
--
2.47.2

View File

@@ -1,323 +0,0 @@
From caaa38a56b7bb5e81bb71f5a6c3489755ebaee98 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@wine-staging.com>
Date: Sat, 6 Feb 2021 12:52:51 -0700
Subject: [PATCH] ntdll: Add tests for NT symlink reparse points.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/ntdll/tests/file.c | 239 +++++++++++++++++++++++++++++++++++++---
1 file changed, 225 insertions(+), 14 deletions(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index 4e3f0f04a3e..48abcd338bb 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -5327,26 +5327,52 @@ static void test_mailslot_name(void)
CloseHandle( device );
}
-static INT build_reparse_buffer(const WCHAR *filename, REPARSE_DATA_BUFFER **pbuffer)
+static INT build_reparse_buffer(const WCHAR *filename, ULONG tag, ULONG flags,
+ REPARSE_DATA_BUFFER **pbuffer)
{
static INT header_size = offsetof(REPARSE_DATA_BUFFER, GenericReparseBuffer);
INT buffer_size, struct_size, data_size, string_len, prefix_len;
WCHAR *subst_dest, *print_dest;
REPARSE_DATA_BUFFER *buffer;
- struct_size = offsetof(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer[0]);
- prefix_len = strlen("\\??\\");
+ switch(tag)
+ {
+ case IO_REPARSE_TAG_MOUNT_POINT:
+ struct_size = offsetof(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer[0]);
+ break;
+ case IO_REPARSE_TAG_SYMLINK:
+ struct_size = offsetof(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer[0]);
+ break;
+ default:
+ return 0;
+ }
+ prefix_len = (flags == SYMLINK_FLAG_RELATIVE) ? 0 : strlen("\\??\\");
string_len = lstrlenW(&filename[prefix_len]);
data_size = (prefix_len + 2 * string_len + 2) * sizeof(WCHAR);
buffer_size = struct_size + data_size;
buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buffer_size);
- buffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
+ buffer->ReparseTag = tag;
buffer->ReparseDataLength = struct_size - header_size + data_size;
- buffer->MountPointReparseBuffer.SubstituteNameLength = (prefix_len + string_len) * sizeof(WCHAR);
- buffer->MountPointReparseBuffer.PrintNameOffset = (prefix_len + string_len + 1) * sizeof(WCHAR);
- buffer->MountPointReparseBuffer.PrintNameLength = string_len * sizeof(WCHAR);
- subst_dest = &buffer->MountPointReparseBuffer.PathBuffer[0];
- print_dest = &buffer->MountPointReparseBuffer.PathBuffer[prefix_len + string_len + 1];
+ switch(tag)
+ {
+ case IO_REPARSE_TAG_MOUNT_POINT:
+ buffer->MountPointReparseBuffer.SubstituteNameLength = (prefix_len + string_len) * sizeof(WCHAR);
+ buffer->MountPointReparseBuffer.PrintNameOffset = (prefix_len + string_len + 1) * sizeof(WCHAR);
+ buffer->MountPointReparseBuffer.PrintNameLength = string_len * sizeof(WCHAR);
+ subst_dest = &buffer->MountPointReparseBuffer.PathBuffer[0];
+ print_dest = &buffer->MountPointReparseBuffer.PathBuffer[prefix_len + string_len + 1];
+ break;
+ case IO_REPARSE_TAG_SYMLINK:
+ buffer->SymbolicLinkReparseBuffer.SubstituteNameLength = (prefix_len + string_len) * sizeof(WCHAR);
+ buffer->SymbolicLinkReparseBuffer.PrintNameOffset = (prefix_len + string_len + 1) * sizeof(WCHAR);
+ buffer->SymbolicLinkReparseBuffer.PrintNameLength = string_len * sizeof(WCHAR);
+ buffer->SymbolicLinkReparseBuffer.Flags = flags;
+ subst_dest = &buffer->SymbolicLinkReparseBuffer.PathBuffer[0];
+ print_dest = &buffer->SymbolicLinkReparseBuffer.PathBuffer[prefix_len + string_len + 1];
+ break;
+ default:
+ return 0;
+ }
lstrcpyW(subst_dest, filename);
lstrcpyW(print_dest, &filename[prefix_len]);
*pbuffer = buffer;
@@ -5363,14 +5389,18 @@ static void test_reparse_points(void)
FILE_BASIC_INFORMATION old_attrib, new_attrib;
static const WCHAR fooW[] = {'f','o','o',0};
static WCHAR volW[] = {'c',':','\\',0};
+ const WCHAR *rel_target = &targetW[1];
WCHAR *dest, *long_path, *abs_target;
REPARSE_GUID_DATA_BUFFER guid_buffer;
static const WCHAR dotW[] = {'.',0};
REPARSE_DATA_BUFFER *buffer = NULL;
DWORD dwret, dwLen, dwFlags, err;
+ WCHAR buf[] = {0,0,0,0};
+ HANDLE handle, token;
IO_STATUS_BLOCK iosb;
UNICODE_STRING nameW;
- HANDLE handle;
+ TOKEN_PRIVILEGES tp;
+ LUID luid;
BOOL bret;
/* Create a temporary folder for the junction point tests */
@@ -5435,7 +5465,7 @@ static void test_reparse_points(void)
win_skip("Failed to open junction point directory handle (0x%lx).\n", GetLastError());
goto cleanup;
}
- buffer_len = build_reparse_buffer(long_path, &buffer);
+ buffer_len = build_reparse_buffer(long_path, IO_REPARSE_TAG_MOUNT_POINT, 0, &buffer);
bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
ok(!bret && GetLastError()==ERROR_INVALID_REPARSE_DATA, "Unexpected error (0x%lx)\n", GetLastError());
HeapFree(GetProcessHeap(), 0, buffer);
@@ -5466,7 +5496,7 @@ static void test_reparse_points(void)
}
dwret = NtQueryInformationFile(handle, &iosb, &old_attrib, sizeof(old_attrib), FileBasicInformation);
ok(dwret == STATUS_SUCCESS, "Failed to get junction point folder's attributes (0x%lx).\n", dwret);
- buffer_len = build_reparse_buffer(long_path, &buffer);
+ buffer_len = build_reparse_buffer(long_path, IO_REPARSE_TAG_MOUNT_POINT, 0, &buffer);
bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
ok(bret, "Failed to create junction point! (0x%lx)\n", GetLastError());
@@ -5513,7 +5543,7 @@ static void test_reparse_points(void)
HeapFree(GetProcessHeap(), 0, buffer);
handle = CreateFileW(reparse_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0);
- buffer_len = build_reparse_buffer(abs_target, &buffer);
+ buffer_len = build_reparse_buffer(abs_target, IO_REPARSE_TAG_MOUNT_POINT, 0, &buffer);
bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
ok(bret, "Failed to create junction point! (0x%lx)\n", GetLastError());
CloseHandle(handle);
@@ -5528,7 +5558,7 @@ static void test_reparse_points(void)
ok(bret, "Failed to create junction point target directory.\n");
handle = CreateFileW(reparse_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0);
- buffer_len = build_reparse_buffer(abs_target, &buffer);
+ buffer_len = build_reparse_buffer(abs_target, IO_REPARSE_TAG_MOUNT_POINT, 0, &buffer);
bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
ok(bret, "Failed to create junction point! (0x%lx)\n", GetLastError());
CloseHandle(handle);
@@ -5541,6 +5571,187 @@ static void test_reparse_points(void)
ok(dwret != (DWORD)~0, "Junction point doesn't exist (attributes: 0x%lx)!\n", dwret);
ok(dwret & FILE_ATTRIBUTE_REPARSE_POINT, "File is not a junction point! (attributes: 0x%lx)\n", dwret);
+ /* Test deleting a junction point's target */
+ dwret = GetFileAttributesW(reparse_path);
+ ok(dwret == 0x410 || broken(dwret == 0x430) /* win2k */ || broken(dwret == 0xc10) /* vista */,
+ "Unexpected junction point attributes (0x%lx != 0x410)!\n", dwret);
+ bret = RemoveDirectoryW(target_path);
+ ok(bret, "Failed to delete junction point target!\n");
+ bret = CreateDirectoryW(target_path, NULL);
+ ok(bret, "Failed to create junction point target directory.\n");
+
+ /* Establish permissions for symlink creation */
+ bret = OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token);
+ ok(bret, "OpenProcessToken failed: %lx\n", GetLastError());
+ bret = LookupPrivilegeValueA(NULL, "SeCreateSymbolicLinkPrivilege", &luid);
+ todo_wine ok(bret || broken(!bret && GetLastError() == ERROR_NO_SUCH_PRIVILEGE) /* winxp */,
+ "LookupPrivilegeValue failed: %lx\n", GetLastError());
+ if (bret)
+ {
+ tp.PrivilegeCount = 1;
+ tp.Privileges[0].Luid = luid;
+ tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+ bret = AdjustTokenPrivileges(token, FALSE, &tp, 0, NULL, NULL);
+ ok(bret, "AdjustTokenPrivileges failed: %lx\n", GetLastError());
+ if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
+ {
+ win_skip("Insufficient permissions to perform symlink tests.\n");
+ goto cleanup;
+ }
+ }
+
+ /* Delete the junction point directory and create a blank slate for symlink tests */
+ bret = RemoveDirectoryW(reparse_path);
+ ok(bret, "Failed to delete junction point!\n");
+ bret = RemoveDirectoryW(target_path);
+ ok(bret, "Failed to delete junction point target!\n");
+ handle = CreateFileW(target_path, GENERIC_READ | GENERIC_WRITE, 0, 0, CREATE_NEW, 0, 0);
+ ok(handle != INVALID_HANDLE_VALUE, "Failed to create symlink target file.\n");
+ bret = WriteFile(handle, fooW, sizeof(fooW), &dwLen, NULL);
+ ok(bret, "Failed to write data to the symlink target file.\n");
+ ok(GetFileSize(handle, NULL) == sizeof(fooW), "target size is incorrect (%ld vs %d)\n",
+ GetFileSize(handle, NULL), (int)sizeof(fooW));
+ CloseHandle(handle);
+
+ /* Create the file symlink */
+ HeapFree(GetProcessHeap(), 0, buffer);
+ handle = CreateFileW(reparse_path, GENERIC_READ | GENERIC_WRITE, 0, 0, CREATE_NEW,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0);
+ ok(handle != INVALID_HANDLE_VALUE, "Failed to create symlink file.\n");
+ dwret = NtQueryInformationFile(handle, &iosb, &old_attrib, sizeof(old_attrib), FileBasicInformation);
+ ok(dwret == STATUS_SUCCESS, "Failed to get symlink file's attributes (0x%lx).\n", dwret);
+ buffer_len = build_reparse_buffer(nameW.Buffer, IO_REPARSE_TAG_SYMLINK, 0, &buffer);
+ bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
+ ok(bret, "Failed to create symlink! (0x%lx)\n", GetLastError());
+ CloseHandle(handle);
+
+ /* Check the size/data of the symlink target when opened with FILE_FLAG_OPEN_REPARSE_POINT */
+ handle = CreateFileW(target_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0);
+ if (handle == INVALID_HANDLE_VALUE)
+ {
+ win_skip("Failed to open symlink file handle (0x%lx).\n", GetLastError());
+ goto cleanup;
+ }
+ ok(GetFileSize(handle, NULL) == sizeof(fooW), "symlink target size does not match (%ld != %d)\n",
+ GetFileSize(handle, NULL), (int)sizeof(fooW));
+ bret = ReadFile(handle, &buf, sizeof(buf), &dwLen, NULL);
+ ok(bret, "Failed to read data from the symlink target.\n");
+ ok(dwLen == sizeof(fooW), "Length of symlink target data does not match (%ld != %d).\n",
+ dwLen, (int)sizeof(fooW));
+ ok(!memcmp(fooW, &buf, sizeof(fooW)), "Symlink target data does not match (%s != %s).\n",
+ wine_dbgstr_wn(buf, dwLen), wine_dbgstr_w(fooW));
+ CloseHandle(handle);
+
+ /* Check deleting a file symlink as if it were a directory */
+ bret = RemoveDirectoryW(reparse_path);
+ ok(!bret, "Succeeded in deleting file symlink as a directory!\n");
+ err = GetLastError();
+ ok(err == ERROR_DIRECTORY,
+ "Expected last error 0x%x for RemoveDirectory on file symlink (actually 0x%lx)!\n",
+ ERROR_DIRECTORY, err);
+ dwret = GetFileAttributesW(reparse_path);
+ ok(dwret != (DWORD)~0, "Symlink doesn't exist (attributes: 0x%lx)!\n", dwret);
+ ok(dwret & FILE_ATTRIBUTE_REPARSE_POINT, "File is not a symlink! (attributes: 0x%lx)\n", dwret);
+
+ /* Delete the symlink as a file */
+ bret = DeleteFileW(reparse_path);
+ ok(bret, "Failed to delete symlink as a file!\n");
+
+ /* Create a blank slate for directory symlink tests */
+ bret = CreateDirectoryW(reparse_path, NULL);
+ ok(bret, "Failed to create junction point directory.\n");
+ dwret = GetFileAttributesW(reparse_path);
+ ok(dwret != (DWORD)~0, "Path doesn't exist (attributes: 0x%lx)!\n", dwret);
+ ok(!(dwret & FILE_ATTRIBUTE_REPARSE_POINT), "File is already a reparse point! (attributes: %lx)\n", dwret);
+ bret = DeleteFileW(target_path);
+ ok(bret, "Failed to delete symlink target!\n");
+ bret = CreateDirectoryW(target_path, NULL);
+ ok(bret, "Failed to create symlink target directory.\n");
+
+ /* Create the directory symlink */
+ HeapFree(GetProcessHeap(), 0, buffer);
+ handle = CreateFileW(reparse_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0);
+ if (handle == INVALID_HANDLE_VALUE)
+ {
+ win_skip("Failed to open symlink directory handle (0x%lx).\n", GetLastError());
+ goto cleanup;
+ }
+ dwret = NtQueryInformationFile(handle, &iosb, &old_attrib, sizeof(old_attrib), FileBasicInformation);
+ ok(dwret == STATUS_SUCCESS, "Failed to get symlink folder's attributes (0x%lx).\n", dwret);
+ buffer_len = build_reparse_buffer(abs_target, IO_REPARSE_TAG_SYMLINK, 0, &buffer);
+ bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
+ ok(bret, "Failed to create symlink! (0x%lx)\n", GetLastError());
+
+ /* Check the file attributes of the symlink */
+ dwret = GetFileAttributesW(reparse_path);
+ ok(dwret != (DWORD)~0, "Symlink doesn't exist (attributes: 0x%lx)!\n", dwret);
+ ok(dwret & FILE_ATTRIBUTE_REPARSE_POINT, "File is not a symlink! (attributes: %lx)\n", dwret);
+
+ /* Read back the symlink */
+ HeapFree(GetProcessHeap(), 0, buffer);
+ buffer_len = sizeof(*buffer) + MAX_PATH*sizeof(WCHAR);
+ buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buffer_len);
+ bret = DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, NULL, 0, (LPVOID)buffer, buffer_len, &dwret, 0);
+ string_len = buffer->SymbolicLinkReparseBuffer.SubstituteNameLength;
+ dest = &buffer->SymbolicLinkReparseBuffer.PathBuffer[buffer->SymbolicLinkReparseBuffer.SubstituteNameOffset/sizeof(WCHAR)];
+ ok(bret, "Failed to read symlink!\n");
+ ok((memcmp(dest, nameW.Buffer, string_len) == 0), "Symlink destination does not match ('%s' != '%s')!\n",
+ wine_dbgstr_w(dest), wine_dbgstr_w(nameW.Buffer));
+ path_len = buffer->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR);
+ path_len += buffer->SymbolicLinkReparseBuffer.PrintNameLength/sizeof(WCHAR);
+ total_len = FIELD_OFFSET(typeof(*buffer), SymbolicLinkReparseBuffer.PathBuffer[path_len+1])
+ - FIELD_OFFSET(typeof(*buffer), GenericReparseBuffer);
+ ok(buffer->ReparseDataLength == total_len, "ReparseDataLength has unexpected value (%d != %d)\n",
+ buffer->ReparseDataLength, total_len);
+
+ /* Delete the symlink */
+ memset(&old_attrib, 0x00, sizeof(old_attrib));
+ old_attrib.LastAccessTime.QuadPart = 0x200deadcafebeef;
+ dwret = NtSetInformationFile(handle, &iosb, &old_attrib, sizeof(old_attrib), FileBasicInformation);
+ ok(dwret == STATUS_SUCCESS, "Failed to set symlink folder's attributes (0x%lx).\n", dwret);
+ memset(&guid_buffer, 0x00, sizeof(guid_buffer));
+ guid_buffer.ReparseTag = IO_REPARSE_TAG_SYMLINK;
+ bret = DeviceIoControl(handle, FSCTL_DELETE_REPARSE_POINT, (LPVOID)&guid_buffer,
+ REPARSE_GUID_DATA_BUFFER_HEADER_SIZE, NULL, 0, &dwret, 0);
+ ok(bret, "Failed to delete symlink! (0x%lx)\n", GetLastError());
+ memset(&new_attrib, 0x00, sizeof(new_attrib));
+ dwret = NtQueryInformationFile(handle, &iosb, &new_attrib, sizeof(new_attrib), FileBasicInformation);
+ ok(dwret == STATUS_SUCCESS, "Failed to get symlink folder's attributes (0x%lx).\n", dwret);
+ ok(old_attrib.LastAccessTime.QuadPart == new_attrib.LastAccessTime.QuadPart,
+ "Symlink folder's access time does not match.\n");
+ CloseHandle(handle);
+
+ /* Create a relative directory symlink */
+ HeapFree(GetProcessHeap(), 0, buffer);
+ handle = CreateFileW(reparse_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0);
+ if (handle == INVALID_HANDLE_VALUE)
+ {
+ win_skip("Failed to open symlink directory handle (0x%lx).\n", GetLastError());
+ goto cleanup;
+ }
+ dwret = NtQueryInformationFile(handle, &iosb, &old_attrib, sizeof(old_attrib), FileBasicInformation);
+ ok(dwret == STATUS_SUCCESS, "Failed to get symlink folder's attributes (0x%lx).\n", dwret);
+ buffer_len = build_reparse_buffer(rel_target, IO_REPARSE_TAG_SYMLINK, SYMLINK_FLAG_RELATIVE, &buffer);
+ bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
+ ok(bret, "Failed to create symlink! (0x%lx)\n", GetLastError());
+
+ /* Read back the relative symlink */
+ HeapFree(GetProcessHeap(), 0, buffer);
+ buffer_len = sizeof(*buffer) + MAX_PATH*sizeof(WCHAR);
+ buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buffer_len);
+ bret = DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, NULL, 0, (LPVOID)buffer, buffer_len, &dwret, 0);
+ ok(bret, "Failed to read relative symlink!\n");
+ string_len = buffer->SymbolicLinkReparseBuffer.SubstituteNameLength;
+ ok(string_len != lstrlenW(rel_target), "Symlink destination length does not match ('%d' != '%d')!\n",
+ string_len, lstrlenW(rel_target));
+ dest = &buffer->SymbolicLinkReparseBuffer.PathBuffer[buffer->SymbolicLinkReparseBuffer.SubstituteNameOffset/sizeof(WCHAR)];
+ ok((memcmp(dest, rel_target, string_len) == 0), "Symlink destination does not match ('%s' != '%s')!\n",
+ wine_dbgstr_w(dest), wine_dbgstr_w(rel_target));
+ CloseHandle(handle);
+
cleanup:
/* Cleanup */
pRtlFreeUnicodeString(&nameW);
--
2.37.2

View File

@@ -1,4 +1,4 @@
From fea1d301c573d3410e2f7d66b21609663ee47880 Mon Sep 17 00:00:00 2001
From 51373e0350ff1b507d7b47d6e5acd84b8af9d328 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@wine-staging.com>
Date: Sat, 6 Feb 2021 12:46:30 -0700
Subject: [PATCH] kernelbase: Add support for moving reparse points with
@@ -6,17 +6,16 @@ Subject: [PATCH] kernelbase: Add support for moving reparse points with
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/kernelbase/file.c | 2 +-
dlls/ntdll/tests/file.c | 12 +++++++++++-
dlls/ntdll/unix/file.c | 23 ++++++++++++++++++++++-
server/fd.c | 6 ++++--
4 files changed, 38 insertions(+), 5 deletions(-)
dlls/kernelbase/file.c | 2 +-
dlls/ntdll/unix/file.c | 24 ++++++++++++++++++++++--
server/fd.c | 6 ++++--
3 files changed, 27 insertions(+), 5 deletions(-)
diff --git a/dlls/kernelbase/file.c b/dlls/kernelbase/file.c
index 51459402e75..d70e0fc833c 100644
index 36045116e43..f1b1326353f 100644
--- a/dlls/kernelbase/file.c
+++ b/dlls/kernelbase/file.c
@@ -2538,7 +2538,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH MoveFileWithProgressW( const WCHAR *source, const
@@ -2597,7 +2597,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH MoveFileWithProgressW( const WCHAR *source, const
InitializeObjectAttributes( &attr, &nt_name, OBJ_CASE_INSENSITIVE, 0, NULL );
status = NtOpenFile( &source_handle, DELETE | SYNCHRONIZE, &attr, &io,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
@@ -25,41 +24,11 @@ index 51459402e75..d70e0fc833c 100644
RtlFreeUnicodeString( &nt_name );
if (!set_ntstatus( status )) goto error;
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index b592036d2d0..6e2c7906644 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -6025,7 +6025,8 @@ static INT build_reparse_buffer(const WCHAR *filename, ULONG tag, ULONG flags,
static void test_reparse_points(void)
{
- WCHAR path[MAX_PATH], reparse_path[MAX_PATH], target_path[MAX_PATH], volnameW[MAX_PATH];
+ WCHAR path[MAX_PATH], reparse_path[MAX_PATH], target_path[MAX_PATH], volnameW[MAX_PATH], new_path[MAX_PATH];
+ static const WCHAR new_reparseW[] = {'\\','n','e','w','_','r','e','p','a','r','s','e',0};
static const WCHAR reparseW[] = {'\\','r','e','p','a','r','s','e',0};
static const WCHAR targetW[] = {'\\','t','a','r','g','e','t',0};
static const WCHAR parentW[] = {'\\','.','.','\\',0};
@@ -6396,6 +6397,15 @@ static void test_reparse_points(void)
wine_dbgstr_w(dest), wine_dbgstr_w(rel_target));
CloseHandle(handle);
+ /* Check moving a reparse point to another location */
+ lstrcpyW(new_path, path);
+ lstrcatW(new_path, parentW);
+ lstrcatW(new_path, new_reparseW);
+ bret = MoveFileW(reparse_path, new_path);
+ ok(bret, "Failed to move and rename reparse point.\n");
+ bret = MoveFileW(new_path, reparse_path);
+ ok(bret, "Failed to move and rename reparse point.\n");
+
cleanup:
/* Cleanup */
pRtlFreeUnicodeString(&nameW);
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index 8e9e28269f8..6385a26bee7 100644
index 3c341a6d702..9076da9f763 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -5675,6 +5675,8 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io,
@@ -5572,6 +5572,8 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io,
unsigned int flags;
UNICODE_STRING name_str, nt_name;
OBJECT_ATTRIBUTES attr;
@@ -68,7 +37,7 @@ index 8e9e28269f8..6385a26bee7 100644
char *unix_name;
if (class == FileRenameInformation)
@@ -5689,6 +5691,20 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io,
@@ -5586,6 +5588,20 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io,
name_str.Length = info->FileNameLength;
name_str.MaximumLength = info->FileNameLength + sizeof(WCHAR);
InitializeObjectAttributes( &attr, &name_str, OBJ_CASE_INSENSITIVE, info->RootDirectory, NULL );
@@ -89,7 +58,7 @@ index 8e9e28269f8..6385a26bee7 100644
status = get_nt_and_unix_names( &attr, &nt_name, &unix_name, FILE_OPEN_IF );
if (status == STATUS_SUCCESS || status == STATUS_NO_SUCH_FILE)
{
@@ -5705,8 +5721,13 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io,
@@ -5602,8 +5618,13 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io,
}
SERVER_END_REQ;
@@ -104,6 +73,14 @@ index 8e9e28269f8..6385a26bee7 100644
free( nt_name.Buffer );
}
else status = STATUS_INVALID_PARAMETER_3;
@@ -5646,7 +5667,6 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io,
status = wine_server_call( req );
}
SERVER_END_REQ;
-
}
free( unix_name );
free( nt_name.Buffer );
diff --git a/server/fd.c b/server/fd.c
index 466259ae567..7f88fcd6e33 100644
--- a/server/fd.c

View File

@@ -1,30 +0,0 @@
From 2cf08dad55bea4bbf5ca37ff0bf4a0553d1f6be3 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Sat, 3 Sep 2022 08:57:05 -0600
Subject: kernelbase: Add test for reparse point copy behavior.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/ntdll/tests/file.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index 808d863ea55..390768f557d 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -5762,6 +5762,12 @@ static void test_reparse_points(void)
bret = MoveFileW(new_path, reparse_path);
ok(bret, "Failed to move and rename reparse point.\n");
+ /* Check copying a reparse point to another location */
+ lstrcpyW(new_path, path);
+ lstrcatW(new_path, new_reparseW);
+ bret = CopyFileW(reparse_path, new_path, TRUE);
+ ok(!bret, "Reparse points cannot be copied.\n");
+
cleanup:
/* Cleanup */
pRtlFreeUnicodeString(&nameW);
--
2.17.1

View File

@@ -5,44 +5,9 @@ Subject: [PATCH] ntdll: Follow reparse points during path resolution.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/ntdll/tests/file.c | 11 ++-
dlls/ntdll/unix/file.c | 196 +++++++++++++++++++++++++++++++++++-----
2 files changed, 184 insertions(+), 23 deletions(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index 9bd4bbdd245..84a0957b040 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -6025,7 +6025,7 @@ static INT build_reparse_buffer(const WCHAR *filename, ULONG tag, ULONG flags,
static void test_reparse_points(void)
{
- WCHAR path[MAX_PATH], reparse_path[MAX_PATH], target_path[MAX_PATH], volnameW[MAX_PATH], new_path[MAX_PATH];
+ WCHAR path[MAX_PATH], reparse_path[MAX_PATH], target_path[MAX_PATH], volnameW[MAX_PATH], new_path[MAX_PATH], thru_path[MAX_PATH];
static const WCHAR new_reparseW[] = {'\\','n','e','w','_','r','e','p','a','r','s','e',0};
static const WCHAR reparseW[] = {'\\','r','e','p','a','r','s','e',0};
static const WCHAR targetW[] = {'\\','t','a','r','g','e','t',0};
@@ -6412,11 +6412,20 @@ static void test_reparse_points(void)
bret = CopyFileW(reparse_path, new_path, TRUE);
ok(!bret, "Reparse points cannot be copied.\n");
+ /* Create a file on the other side of a reparse point */
+ lstrcpyW(thru_path, reparse_path);
+ lstrcatW(thru_path, new_reparseW);
+ handle = CreateFileW(thru_path, GENERIC_READ | GENERIC_WRITE, 0, 0, CREATE_NEW, 0, 0);
+ ok( handle != INVALID_HANDLE_VALUE, "Failed to create file on other side of reparse point: %lx.\n", GetLastError() );
+ CloseHandle(handle);
+
cleanup:
/* Cleanup */
pRtlFreeUnicodeString(&nameW);
HeapFree(GetProcessHeap(), 0, long_path);
HeapFree(GetProcessHeap(), 0, buffer);
+ bret = DeleteFileW(thru_path);
+ ok(bret, "Failed to delete file on other side of junction point!\n");
bret = RemoveDirectoryW(reparse_path);
ok(bret, "Failed to remove temporary reparse point directory!\n");
bret = RemoveDirectoryW(target_path);
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index f3274478ae2..860e563f69d 100644
--- a/dlls/ntdll/unix/file.c

View File

@@ -1,4 +1,4 @@
From f1675a9b37980cafd0b6f76e23ef8b042b60bb1e Mon Sep 17 00:00:00 2001
From 5b94720ada0b6f75ddff60cf19472a2685dbeaf0 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Sun, 4 Sep 2022 13:19:16 -0600
Subject: [PATCH] ntdll: Allow reparse points to target the applicable Unix
@@ -9,14 +9,14 @@ the user to follow the symlink outside of Wine.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/ntdll/unix/file.c | 129 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 129 insertions(+)
dlls/ntdll/unix/file.c | 118 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 118 insertions(+)
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index f2e182d9076..63a27b89e20 100644
index c54fd1119e1..33f26ceb89a 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -3577,6 +3577,125 @@ static NTSTATUS get_reparse_target( UNICODE_STRING *nt_target, REPARSE_DATA_BUFF
@@ -3712,6 +3712,114 @@ static NTSTATUS get_reparse_target( UNICODE_STRING *nt_target, REPARSE_DATA_BUFF
}
@@ -50,18 +50,7 @@ index f2e182d9076..63a27b89e20 100644
+ d = dirname( unix_path );
+ if (d != unix_path) strcpy( unix_path, d );
+ strcat( unix_path, "/");
+ for (;;)
+ {
+ nt_path = malloc( nt_path_len * sizeof(WCHAR) );
+ if (!nt_path)
+ {
+ free( unix_path );
+ return STATUS_NO_MEMORY;
+ }
+ status = wine_unix_to_nt_file_name( unix_path, nt_path, &nt_path_len );
+ if (status != STATUS_BUFFER_TOO_SMALL) break;
+ free( nt_path );
+ }
+ status = unix_to_nt_file_name( unix_path, &nt_path, FILE_OPEN );
+ free( unix_path );
+ if (status != STATUS_SUCCESS)
+ return status;
@@ -142,7 +131,7 @@ index f2e182d9076..63a27b89e20 100644
/*
* Retrieve the unix name corresponding to a file handle, remove that directory, and then symlink
* the requested directory to the location of the old directory.
@@ -3710,6 +3829,16 @@ NTSTATUS create_reparse_point(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
@@ -3845,6 +3953,16 @@ NTSTATUS create_reparse_point(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
link_dir_fd = fd;
}
@@ -160,5 +149,5 @@ index f2e182d9076..63a27b89e20 100644
if (!renameat2( -1, tmplink, -1, unix_src, RENAME_EXCHANGE ))
{
--
2.43.0
2.47.2

View File

@@ -5,60 +5,9 @@ Subject: ntdll: Always report symbolic links as containing zero bytes.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/ntdll/tests/file.c | 32 ++++++++++++++++++++++++++++++++
dlls/ntdll/unix/file.c | 4 ++++
2 files changed, 36 insertions(+)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index a0b84849490..35ba5f03097 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -5396,6 +5396,7 @@ static void test_reparse_points(void)
static const WCHAR dotW[] = {'.',0};
REPARSE_DATA_BUFFER *buffer = NULL;
DWORD dwret, dwLen, dwFlags, err;
+ WIN32_FILE_ATTRIBUTE_DATA fad;
WCHAR buf[] = {0,0,0,0};
HANDLE handle, token;
IO_STATUS_BLOCK iosb;
@@ -5626,6 +5627,37 @@ static void test_reparse_points(void)
ok(bret, "Failed to create symlink! (0x%lx)\n", GetLastError());
CloseHandle(handle);
+ /* Check the size of the symlink */
+ bret = GetFileAttributesExW(reparse_path, GetFileExInfoStandard, &fad);
+ ok(bret, "Failed to read file attributes from the symlink target.\n");
+ ok(fad.nFileSizeLow == 0 && fad.nFileSizeHigh == 0, "Size of symlink is not zero.\n");
+ handle = CreateFileW(reparse_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0);
+ ok(handle != INVALID_HANDLE_VALUE, "Failed to open symlink file.\n");
+ ok(GetFileSize(handle, NULL) == 0, "symlink size is not zero\n");
+ bret = ReadFile(handle, &buf, sizeof(buf), &dwLen, NULL);
+ todo_wine ok(bret, "Failed to read data from the symlink.\n");
+ ok(dwLen == 0, "Length of symlink data is not zero.\n");
+ CloseHandle(handle);
+
+ /* Check the size/data of the symlink target */
+ handle = CreateFileW(reparse_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS, 0);
+ if (handle == INVALID_HANDLE_VALUE)
+ {
+ win_skip("Failed to open symlink file handle (0x%lx).\n", GetLastError());
+ goto cleanup;
+ }
+ ok(GetFileSize(handle, NULL) == sizeof(fooW), "symlink target size does not match (%ld != %d)\n",
+ GetFileSize(handle, NULL), (int)sizeof(fooW));
+ bret = ReadFile(handle, &buf, sizeof(buf), &dwLen, NULL);
+ ok(bret, "Failed to read data from the symlink.\n");
+ ok(dwLen == sizeof(fooW), "Length of symlink target data does not match (%ld != %d).\n",
+ dwLen, (int)sizeof(fooW));
+ ok(!memcmp(fooW, &buf, sizeof(fooW)), "Symlink target data does not match (%s != %s).\n",
+ wine_dbgstr_wn(buf, dwLen), wine_dbgstr_w(fooW));
+ CloseHandle(handle);
+
/* Check the size/data of the symlink target when opened with FILE_FLAG_OPEN_REPARSE_POINT */
handle = CreateFileW(target_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0);
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index f298b1f7a6c..caa454c024f 100644
--- a/dlls/ntdll/unix/file.c

Some files were not shown because too many files have changed in this diff Show More