ntdll: test to get and set junctions
tkho at ucla.edu
tkho at ucla.edu
Tue Mar 14 21:20:21 CST 2006
Greetings,
The following patch adds a conformance test to get/set NTFS mount point
junctions. Junctions may be useful in allowing some applications to
transparently handle unix sym links.
I added a simple header file include/ntifs.h that is also duplicated in the
dlls/ntdll/tests directory. The required structs and defines aren't found
in the normal sdk, and I couldn't think of a better way to address this
duplication.
Comments appreciated!
Regards,
Thomas Kho
2006-03-14 Thomas Kho <tkho at ucla.edu>
* dlls/ntdll/tests/Makefile.in, dlls/ntdll/tests/file.c,
dlls/ntdll/tests/ntifs.h, include/ntifs.h
include/winnt.h
ntdll: added test to get/set NTFS mount point junctions
dlls/ntdll/tests/Makefile.in | 1
dlls/ntdll/tests/file.c | 165 +++++++++++++++++++++++++++++++++++++++++++
dlls/ntdll/tests/ntifs.h | 66 +++++++++++++++++
include/ntifs.h | 63 ++++++++++++++++
include/winnt.h | 4 +
5 files changed, 299 insertions(+)
Signed-off-by: Thomas Kho <tkho at ucla.edu>
Index: dlls/ntdll/tests/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/ntdll/tests/Makefile.in,v
retrieving revision 1.17
diff -u -r1.17 Makefile.in
--- dlls/ntdll/tests/Makefile.in 17 Jan 2006 12:38:54 -0000 1.17
+++ dlls/ntdll/tests/Makefile.in 15 Mar 2006 02:56:19 -0000
@@ -11,6 +11,7 @@
env.c \
error.c \
exception.c \
+ file.c \
generated.c \
info.c \
large_int.c \
Index: include/winnt.h
===================================================================
RCS file: /home/wine/wine/include/winnt.h,v
retrieving revision 1.229
diff -u -r1.229 winnt.h
--- include/winnt.h 15 Feb 2006 13:03:05 -0000 1.229
+++ include/winnt.h 15 Mar 2006 02:56:21 -0000
@@ -3750,6 +3750,8 @@
#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000
#define FILE_ATTRIBUTE_ENCRYPTED 0x00004000
+#define FILE_FLAG_OPEN_REPARSE_POINT 0x00200000
+
/* File notification flags */
#define FILE_NOTIFY_CHANGE_FILE_NAME 0x00000001
#define FILE_NOTIFY_CHANGE_DIR_NAME 0x00000002
@@ -3815,6 +3817,8 @@
#define REG_QWORD 11 /* QWORD in little endian format */
#define REG_QWORD_LITTLE_ENDIAN 11 /* QWORD in little endian format */
+#define IO_REPARSE_TAG_MOUNT_POINT 0xa0000003
+
/* ----------------------------- begin power management --------------------- */
typedef enum _LATENCY_TIME {
--- /dev/null 2006-02-21 13:00:58.980424750 -0800
+++ include/ntifs.h 2006-03-14 18:55:53.974114000 -0800
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2006 Google (Thomas Kho)
+ *
+ * This library 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 Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __WINE_NTIFS_H
+#define __WINE_NTIFS_H
+
+/* Definitions necessary to get/set mount point junctions.
+ *
+ * Derived from Sysinternals Junction:
+ * http://www.sysinternals.com/Utilities/Junction.html
+ *
+ * Sysinternals' REPARSE_MOUNTPOINT_DATA_BUFFER is a mangled
+ * REPARSE_DATA_BUFFER, which ends up okay because of little-endian arch. The
+ * same REPARSE_DATA_BUFFER can be also used to set junctions.
+ */
+
+typedef struct _REPARSE_DATA_BUFFER {
+ ULONG ReparseTag;
+ USHORT ReparseDataLength;
+ USHORT Reserved;
+ union {
+ struct {
+ USHORT SubstituteNameOffset;
+ USHORT SubstituteNameLength;
+ USHORT PrintNameOffset;
+ USHORT PrintNameLength;
+ WCHAR PathBuffer[1];
+ } SymbolicLinkReparseBuffer;
+ struct {
+ USHORT SubstituteNameOffset;
+ USHORT SubstituteNameLength;
+ USHORT PrintNameOffset;
+ USHORT PrintNameLength;
+ WCHAR PathBuffer[1];
+ } MountPointReparseBuffer;
+ struct {
+ UCHAR DataBuffer[1];
+ } GenericReparseBuffer;
+ };
+} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
+
+#define REPARSE_DATA_BUFFER_HEADER_SIZE 8
+
+#ifndef MAXIMUM_REPARSE_DATA_BUFFER_SIZE
+#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE (16*1024)
+#endif
+
+#endif /* __WINE_NTIFS_H */
--- /dev/null 2006-02-21 13:00:58.980424750 -0800
+++ dlls/ntdll/tests/ntifs.h 2006-03-14 18:56:09.665564000 -0800
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2006 Google (Thomas Kho)
+ *
+ * This library 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 Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* NOTE: This is the same as include/ntifs.h, except we need a copy here because
+ * most builds of the conformance test on Windows would fail otherwise */
+
+#ifndef __WINE_NTIFS_H
+#define __WINE_NTIFS_H
+
+/* Definitions necessary to get/set mount point junctions.
+ *
+ * Derived from Sysinternals Junction:
+ * http://www.sysinternals.com/Utilities/Junction.html
+ *
+ * Sysinternals' REPARSE_MOUNTPOINT_DATA_BUFFER is a mangled
+ * REPARSE_DATA_BUFFER, which ends up okay because of little-endian arch. The
+ * same REPARSE_DATA_BUFFER can be also used to set junctions.
+ */
+
+typedef struct _REPARSE_DATA_BUFFER {
+ ULONG ReparseTag;
+ USHORT ReparseDataLength;
+ USHORT Reserved;
+ union {
+ struct {
+ USHORT SubstituteNameOffset;
+ USHORT SubstituteNameLength;
+ USHORT PrintNameOffset;
+ USHORT PrintNameLength;
+ WCHAR PathBuffer[1];
+ } SymbolicLinkReparseBuffer;
+ struct {
+ USHORT SubstituteNameOffset;
+ USHORT SubstituteNameLength;
+ USHORT PrintNameOffset;
+ USHORT PrintNameLength;
+ WCHAR PathBuffer[1];
+ } MountPointReparseBuffer;
+ struct {
+ UCHAR DataBuffer[1];
+ } GenericReparseBuffer;
+ };
+} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
+
+#define REPARSE_DATA_BUFFER_HEADER_SIZE 8
+
+#ifndef MAXIMUM_REPARSE_DATA_BUFFER_SIZE
+#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE (16*1024)
+#endif
+
+#endif /* __WINE_NTIFS_H */
--- /dev/null 2006-02-21 13:00:58.980424750 -0800
+++ dlls/ntdll/tests/file.c 2006-03-14 17:58:04.125459000 -0800
@@ -0,0 +1,165 @@
+/*
+ * Unit test suite for ntdll file functions
+ *
+ * Copyright 2006 Google (Thomas Kho)
+ *
+ * This library 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 Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <wchar.h>
+
+#include "ntdll_test.h"
+#include "wine/unicode.h"
+
+/* defines for FSCTL_SET_REPARSE_POINT and FSCTL_GET_REPARSE_POINT */
+#include <winioctl.h>
+
+#include "ntifs.h"
+
+/* Make a valid temp filename
+ * free() return value */
+static char *make_temp_name(void)
+{
+ HANDLE hFile;
+ char temp_path[MAX_PATH];
+ char *filename = malloc(MAX_PATH);
+ static const char prefix[] = "pfx";
+ DWORD ret;
+
+ ret = GetTempPath(MAX_PATH, temp_path);
+ if (ret == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+ return NULL;
+ ok(ret != 0, "GetTempPath error %ld\n", GetLastError());
+ ok(ret < MAX_PATH, "temp path should fit into MAX_PATH\n");
+
+ ok(GetTempFileName(temp_path, prefix, 0, filename),
+ "GetTempFileName error %ld\n", GetLastError());
+
+ hFile = CreateFile(filename, GENERIC_READ, 0, NULL,
+ CREATE_NEW, FILE_FLAG_RANDOM_ACCESS, 0);
+ ok(hFile == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_EXISTS,
+ "New file not created\n");
+
+ ok(DeleteFile(filename), "DeleteFile: error %ld\n", GetLastError());
+ return filename;
+}
+
+/* Create a temp dir and return its filename
+ * free() return value */
+static char *create_temp_dir()
+{
+ char *dirname = make_temp_name();
+ ok(CreateDirectory(dirname, NULL) != 0, "can't create directory: %ld\n",
+ GetLastError());
+ return dirname;
+}
+
+static void test_ReparsePoints_check_NTFS(void)
+{
+ char filesys[MAX_PATH+1];
+ char *drive = make_temp_name();
+ drive[3] = '\0';
+ ok(GetVolumeInformation(drive, NULL, 0, NULL, 0, 0, filesys, MAX_PATH+1)
+ != 0, "error: %ld\n", GetLastError());
+ ok(!strcmp(filesys, "NTFS"), "fs reported: %s\n", filesys);
+ free(drive);
+}
+
+static void test_ReparsePoints_create(char *target, char *reparse_point,
+ WCHAR *wreparse_point)
+{
+ DWORD len;
+ REPARSE_DATA_BUFFER *rdb = calloc(MAXIMUM_REPARSE_DATA_BUFFER_SIZE, 1);
+ HANDLE hReparsePoint = CreateFile(reparse_point, GENERIC_WRITE,
+ 0, NULL, OPEN_EXISTING,
+ FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, NULL);
+
+ ok(hReparsePoint != INVALID_HANDLE_VALUE, "error: %ld\n", GetLastError());
+
+ rdb->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
+ wcscpy(rdb->MountPointReparseBuffer.PathBuffer, wreparse_point);
+ rdb->MountPointReparseBuffer.SubstituteNameLength =
+ wcslen(rdb->MountPointReparseBuffer.PathBuffer) * sizeof(WCHAR);
+ rdb->MountPointReparseBuffer.PrintNameOffset =
+ rdb->MountPointReparseBuffer.SubstituteNameLength + sizeof(WCHAR);
+ rdb->ReparseDataLength =
+ rdb->MountPointReparseBuffer.SubstituteNameLength + 12;
+
+ todo_wine {
+ ok(DeviceIoControl(hReparsePoint, FSCTL_SET_REPARSE_POINT, rdb,
+ rdb->ReparseDataLength
+ + REPARSE_DATA_BUFFER_HEADER_SIZE, NULL, 0, &len,
+ NULL) != 0, "error: %ld\n", GetLastError());
+ }
+ ok(CloseHandle(hReparsePoint) != 0, "error: %ld\n", GetLastError());
+ free(rdb);
+}
+
+static void test_ReparsePoints_created(char *reparse_point,
+ WCHAR *wreparse_point)
+{
+ DWORD len;
+ HANDLE dir;
+ REPARSE_DATA_BUFFER *rdb = calloc(MAXIMUM_REPARSE_DATA_BUFFER_SIZE, 1);
+
+ todo_wine {
+ ok((GetFileAttributes(reparse_point) & FILE_ATTRIBUTE_REPARSE_POINT)
+ != 0, "not reparse point\n");
+ }
+ dir = CreateFile(reparse_point, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
+ OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT
+ |FILE_FLAG_BACKUP_SEMANTICS, NULL);
+
+ todo_wine {
+ ok(DeviceIoControl(dir, FSCTL_GET_REPARSE_POINT, NULL, 0, rdb,
+ MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &len, NULL) != 0,
+ "error: %ld\n", GetLastError());
+ ok(rdb->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT,
+ "error: ReparseTag: 0x%lx\n", rdb->ReparseTag);
+ ok(!wcscmp(rdb->MountPointReparseBuffer.PathBuffer
+ + (rdb->MountPointReparseBuffer.SubstituteNameOffset
+ / sizeof(WCHAR)), wreparse_point), "error\n");
+ }
+ ok(CloseHandle(dir) != 0, "error: %ld\n", GetLastError());
+ free(rdb);
+}
+
+static void test_ReparsePoints(void)
+{
+ char *target;
+ char *reparse_point;
+ WCHAR wreparse_point[MAX_PATH+1] = {'\\', '?', '?', '\\'};
+
+ test_ReparsePoints_check_NTFS();
+
+ reparse_point = create_temp_dir();
+ target = create_temp_dir();
+ mbstowcs(wreparse_point+4, target, strlen(target)+1);
+
+ test_ReparsePoints_create(target, reparse_point, wreparse_point);
+ test_ReparsePoints_created(reparse_point, wreparse_point);
+
+ RemoveDirectory(target);
+ RemoveDirectory(reparse_point);
+
+ free(target);
+ free(reparse_point);
+}
+
+START_TEST(file)
+{
+ test_ReparsePoints();
+}
More information about the wine-patches
mailing list