Author: mnordell
Date: Mon Sep 24 12:20:06 2012
New Revision: 57374
URL:
http://svn.reactos.org/svn/reactos?rev=57374&view=rev
Log:
Add test for RtlDosPathNameToNtPathName_U. This time with the actual test file too.
Added:
trunk/rostests/apitests/ntdll/RtlDosPathNameToNtPathName_U.c (with props)
Added: trunk/rostests/apitests/ntdll/RtlDosPathNameToNtPathName_U.c
URL:
http://svn.reactos.org/svn/reactos/trunk/rostests/apitests/ntdll/RtlDosPath…
==============================================================================
--- trunk/rostests/apitests/ntdll/RtlDosPathNameToNtPathName_U.c (added)
+++ trunk/rostests/apitests/ntdll/RtlDosPathNameToNtPathName_U.c [iso-8859-1] Mon Sep 24
12:20:06 2012
@@ -1,0 +1,437 @@
+/*
+ * PROJECT: ReactOS api tests
+ * LICENSE: GPLv2+ - See COPYING in the top level directory
+ * PURPOSE: Test for RtlDosPathNameToNtPathName_U
+ * PROGRAMMER: Mike "tamlin" Nordell
+ */
+/* TODO:
+ * - Make the code UNICODE aware. If a user is inside a directory with
+ * non-ANSI characters somewhere in the path, all bets are currently off.
+ * - Remove hard-coded path size limits.
+ * - Un-tabify to match style of other code.
+ */
+
+/* Test to see that ntdll.RtlDosPathNameToNtPathName_U behaves _exactly_
+ * like Windows with all possible input to it.
+ * - relative path.
+ * - absolute paths
+ * - \\.\C:\foo
+ * - \\.\C:\foo\
+ * - \\?\C:\foo
+ * - \\?\C:\foo\
+ * - \??\C:
+ * - \??\C:\
+ *
+ * Caveat: The "\??\*" form behaves different depending on Windows version.
+ *
+ * Code is assumed to be compiled as 32-bit "ANSI" (i.e. with _UNICODE)
undefined.
+ */
+
+// Enable this define to compile the test as a ReactOS auto-test.
+// Disable it to compile on plain Win32, to test-run and get info.
+#define COMPILE_AS_ROSTEST
+
+#ifndef COMPILE_AS_ROSTEST
+# define PRINT_INFO // Also print, in addition to testing
+# include <windows.h>
+# include <stdio.h>
+# include <stddef.h>
+#else /* Compile for ReactOS or wine */
+# define WIN32_NO_STATUS
+# include <stdio.h>
+# include <wine/test.h>
+# include <pseh/pseh2.h>
+# include <ndk/rtlfuncs.h>
+#endif
+
+/*
+BOOLEAN
+NTAPI
+RtlDosPathNameToNtPathName_U(IN PCWSTR DosName,
+ OUT PUNICODE_STRING NtName,
+ OUT PCWSTR *PartName,
+ OUT PRTL_RELATIVE_NAME_U RelativeName)
+*/
+
+#ifndef COMPILE_AS_ROSTEST
+
+typedef struct UNICODE_STRING {
+ USHORT Length;
+ USHORT MaximumLength;
+ PWSTR Buffer;
+} UNICODE_STRING, *PUNICODE_STRING;
+
+typedef struct _RTLP_CURDIR_REF
+{
+ LONG RefCount;
+ HANDLE Handle;
+} RTLP_CURDIR_REF, *PRTLP_CURDIR_REF;
+
+typedef struct RTL_RELATIVE_NAME_U {
+ UNICODE_STRING RelativeName;
+ HANDLE ContainingDirectory;
+ PRTLP_CURDIR_REF CurDirRef;
+} RTL_RELATIVE_NAME_U, *PRTL_RELATIVE_NAME_U;
+
+typedef BOOLEAN (__stdcall
*RtlDosPathNameToNtPathName_U_t)(PCWSTR,PUNICODE_STRING,PCWSTR*,PRTL_RELATIVE_NAME_U);
+
+RtlDosPathNameToNtPathName_U_t RtlDosPathNameToNtPathName_U;
+
+#endif // !COMPILE_AS_ROSTEST
+
+
+static void report_error(const char* pszErr)
+{
+#ifdef COMPILE_AS_ROSTEST
+ ok(FALSE, "%s\n", pszErr);
+#else
+ printf("\a** %s!\n", pszErr);
+#endif
+}
+
+
+#ifndef COMPILE_AS_ROSTEST
+static void prucs(const char* pszDesc, UNICODE_STRING* pucs)
+{
+ WCHAR wszTmp[512];
+ memcpy(wszTmp, pucs->Buffer, pucs->Length);
+ wszTmp[pucs->Length/2] = 0;
+ printf("%-12s: \"%S\"\n", pszDesc, wszTmp);
+}
+#endif
+
+// Test RtlDosPathNameToNtPathName_U .
+// pwszExpected shall contain the expected result for NtName
+// *without* the leading "\??\".
+// pwszExpectedPartName shall contain the expected result for PartName.
+// NULL Expected means result is expected to be NULL too.
+static void test2(LPCWSTR pwsz, LPCWSTR pwszExpected, LPCWSTR pwszExpectedPartName)
+{
+ UNICODE_STRING NtName;
+ PWSTR PartName;
+ RTL_RELATIVE_NAME_U RelativeName;
+ BOOLEAN bOK;
+
+ bOK = RtlDosPathNameToNtPathName_U(pwsz, &NtName, (PCWSTR*)&PartName,
&RelativeName);
+
+ if (!bOK) {
+ report_error("RtlDosPathNameToNtPathName_U failed");
+ printf("input: \"%S\"\n", pwsz);
+ return;
+// exit(1);
+ }
+
+#if !defined(COMPILE_AS_ROSTEST) && defined(PRINT_INFO)
+ printf("--------------------------\n");
+ printf("in : \"%S\"\n", pwsz);
+ prucs("NtName", &NtName);
+ if (PartName) {
+ printf("PartName : \"%S\"\n", PartName);
+ } else {
+ // This is not the place to test that printf handles NULL strings.
+ printf("PartName : (null)\n");
+ }
+// prucs("RelativeName", &RelativeName.RelativeName);
+#endif
+
+ // Disregarding input, output (NtName) shall always start with "\??\".
+ if (memcmp(NtName.Buffer, L"\\??\\", 8)) {
+ report_error("NtName does not start with \"\\??\\\"");
+ return;
+// exit(1);
+ }
+ if (pwszExpected) {
+ PWSTR pwszActual = NtName.Buffer + 4;
+ const size_t lenExp = wcslen(pwszExpected);
+ const size_t lenAct = (NtName.Length - 8) / 2;
+ if (lenExp != lenAct ||
+ memcmp(pwszActual, pwszExpected, lenExp * 2))
+ {
+ report_error("Actual NtName does not match expectations!");
+ printf("Expected: %2u chars \"%S\"\n", lenExp, pwszExpected);
+ printf("Actual : %2u chars \"%S\"\n", lenAct, lenAct ? pwszActual
: L"(null)");
+ return;
+// exit(1);
+ }
+ } else
+ if (NtName.Length)
+ {
+ PWSTR pwszActual = NtName.Buffer + 4;
+ const size_t lenAct = (NtName.Length - 8) / 2;
+ report_error("Unexpected NtName (expected NULL)");
+ printf("Actual : %2u chars \"%S\"\n", lenAct, pwszActual);
+ }
+
+ if (pwszExpectedPartName) {
+ if (!PartName) {
+ report_error("Actual PartName is unexpectedly NULL!");
+ printf("Expected: \"%S\"\n", pwszExpectedPartName);
+ return;
+// exit(1);
+ }
+ if (wcscmp(PartName, pwszExpectedPartName)) {
+ report_error("Actual PartName does not match expected!");
+ printf("Expected: \"%S\"\n", pwszExpectedPartName);
+ printf("Actual : \"%S\"\n", PartName);
+ return;
+ }
+ } else
+ if (PartName)
+ {
+ report_error("Unexpected PartName (expected NULL)");
+ printf("Actual : %S\n", PartName);
+ }
+}
+
+// NULL Expected means result is expected to be NULL too.
+static void test(const char* psz, const char* pszExpected, const char*
pszExpectedPartName)
+{
+ WCHAR wszTmp1[512];
+ WCHAR wszTmp2[512];
+ WCHAR wszTmp3[512];
+ LPCWSTR p2 = 0;
+ LPCWSTR p3 = 0;
+ swprintf(wszTmp1, L"%S", psz);
+ if (pszExpected) {
+ swprintf(wszTmp2, L"%S", pszExpected);
+ p2 = wszTmp2;
+ }
+ if (pszExpectedPartName) {
+ swprintf(wszTmp3, L"%S", pszExpectedPartName);
+ p3 = wszTmp3;
+ }
+ test2(wszTmp1, p2, p3);
+}
+
+
+typedef struct DirComponents
+{
+ char szCD[512];
+ char szCDPlusSlash[512];
+ char* pszLastCDComponent;
+ char szCurDrive[4];
+ char szParentDir[512];
+ char szParentDirPlusSlash[512];
+ char szNextLastCDComponent[260];
+ const char* pszNextLastCDComponent;
+ const char* pszParentDir;
+ const char* pszParentDirPlusSlash;
+} DirComponents;
+
+
+static void InitDirComponents(DirComponents* p)
+{
+ p->pszNextLastCDComponent = 0;
+ p->pszParentDir = 0;
+ p->pszParentDirPlusSlash = 0;
+
+ GetCurrentDirectory(sizeof(p->szCD) / sizeof(*p->szCD), p->szCD);
+
+ if (strlen(p->szCD) < 2 || p->szCD[1] != ':') {
+ printf("Expected curdir to be a drive letter. It's not. It's
\"%s\"\n", p->szCD);
+#ifdef COMPILE_AS_ROSTEST
+ ok(FALSE, "Expected curdir to be a drive letter. It's not. It's
\"%s\"\n", p->szCD);
+#endif
+ exit(1);
+ }
+
+ // Note that if executed from the root directory, a slash already
+ // is appended. Take the opportunity to verify this.
+ if (p->szCD[2] != '\\') {
+ printf("CD is missing a slash as its third character! \"%s\"\n",
p->szCD);
+#ifdef COMPILE_AS_ROSTEST
+ ok(FALSE, "CD is missing a slash as its third character! \"%s\"\n",
p->szCD);
+#endif
+ exit(1);
+ }
+
+ strcpy(p->szCDPlusSlash, p->szCD);
+ if (strlen(p->szCD) > 3) {
+ // Append trailing backslash
+ strcat(p->szCDPlusSlash, "\\");
+ }
+
+ memcpy(p->szCurDrive, p->szCD, 2);
+ p->szCurDrive[2] = 0;
+
+ p->pszLastCDComponent = strrchr(p->szCD, '\\');
+ if (p->pszLastCDComponent)
+ {
+ // We have a parent directory
+ memcpy(p->szParentDir, p->szCD, p->pszLastCDComponent - p->szCD);
+ p->szParentDir[p->pszLastCDComponent - p->szCD] = 0;
+ p->pszParentDir = p->szParentDir;
+ if (strlen(p->szParentDir) == 2 && p->szParentDir[1] == ':') {
+ // When run from root directory, this is expected to
+ // have a trailing backslash
+ strcat(p->szParentDir, "\\");
+ }
+ strcpy(p->szParentDirPlusSlash, p->szParentDir);
+ if (p->szParentDirPlusSlash[strlen(p->szParentDirPlusSlash)-1] != '\\')
{
+ strcat(p->szParentDirPlusSlash, "\\");
+ }
+ p->pszParentDirPlusSlash = p->szParentDirPlusSlash;
+
+ // Check if we have a directory above that too.
+ *p->pszLastCDComponent = 0;
+ p->pszNextLastCDComponent = strrchr(p->szCD, '\\');
+ *p->pszLastCDComponent = '\\';
+ if (p->pszNextLastCDComponent) {
+ ++p->pszNextLastCDComponent; // skip the leading slash
+ if (p->pszNextLastCDComponent + 1 >= p->pszLastCDComponent) {
+ p->pszNextLastCDComponent = 0;
+ } else {
+ const size_t siz = p->pszLastCDComponent - p->pszNextLastCDComponent;
+ memcpy(p->szNextLastCDComponent, p->pszNextLastCDComponent, siz);
+ p->szNextLastCDComponent[siz] = 0;
+ p->pszNextLastCDComponent = p->szNextLastCDComponent;
+ }
+ }
+ }
+ if (p->pszLastCDComponent && p->pszLastCDComponent[1] == 0) {
+ // If the backslash is the last character in the path,
+ // this is a NULL-component.
+ p->pszLastCDComponent = 0;
+ } else {
+ ++p->pszLastCDComponent; // skip the leading slash
+ }
+}
+
+
+#ifndef COMPILE_AS_ROSTEST
+static void InitFunctionPointer()
+{
+ HINSTANCE hDll = LoadLibrary("ntdll");
+ if (!hDll) {
+ printf("Major failure. Couldn't even load ntdll!\n");
+ exit(1);
+ }
+ RtlDosPathNameToNtPathName_U =
+ (RtlDosPathNameToNtPathName_U_t)GetProcAddress(hDll,
"RtlDosPathNameToNtPathName_U");
+ if (!hDll) {
+ printf("Major failure. Couldn't get RtlDosPathNameToNtPathName_U!\n");
+ exit(1);
+ }
+}
+#endif // !COMPILE_AS_ROSTEST
+
+
+#ifdef COMPILE_AS_ROSTEST
+START_TEST(RtlDosPathNameToNtPathName_U)
+#else
+int main()
+#endif
+{
+#if defined(PRINT_INFO)
+#ifdef COMPILE_AS_ROSTEST
+ PPEB Peb = NtCurrentPeb();
+ const DWORD dwWinVer = (DWORD)(Peb->OSMinorVersion << 8) |
Peb->OSMajorVersion;
+#else
+ const DWORD dwWinVer = GetVersion();
+#endif
+ const BYTE WinVerMaj = (BYTE)dwWinVer;
+ const BYTE WinVerMin = HIBYTE(LOWORD(dwWinVer));
+#endif // PRINT_INFO
+
+ DirComponents cd;
+
+#ifndef COMPILE_AS_ROSTEST
+ InitFunctionPointer();
+#endif
+
+ InitDirComponents(&cd);
+
+#if defined(PRINT_INFO)
+ printf("WinVer: %d.%d\n", WinVerMaj, WinVerMin);
+ printf("pszLastCDComponent \"%s\"\n", cd.pszLastCDComponent);
+ printf("pszNextLastCDComponent \"%s\"\n",
cd.pszNextLastCDComponent);
+ printf("pszParentDir \"%s\"\n", cd.pszParentDir);
+ printf("pszParentDirPlusSlash \"%s\"\n",
cd.pszParentDirPlusSlash);
+#endif
+
+
+#define PREP0
+#define PREP1 "\\\\.\\"
+#define PREP2 "\\\\?\\"
+
+ // The following tests shall return strictly defined strings,
+ // why we can use hard-coded expectations..
+ test(PREP1 "C:" , "C:" , "C:");
+ test(PREP2 "C:" , "C:" , "C:");
+ test(PREP0 "C:\\" , "C:\\" , NULL);
+ test(PREP1 "C:\\" , "C:\\" , NULL);
+ test(PREP2 "C:\\" , "C:\\" , NULL);
+ test(PREP0 "C:\\foo" , "C:\\foo" , "foo");
+ test(PREP1 "C:\\foo" , "C:\\foo" , "foo");
+ test(PREP2 "C:\\foo" , "C:\\foo" , "foo");
+ test(PREP0 "C:\\foo\\" , "C:\\foo\\" , NULL);
+ test(PREP1 "C:\\foo\\" , "C:\\foo\\" , NULL);
+ test(PREP2 "C:\\foo\\" , "C:\\foo\\" , NULL);
+ test(PREP0 "C:\\foo\\bar" , "C:\\foo\\bar" , "bar");
+ test(PREP1 "C:\\foo\\bar" , "C:\\foo\\bar" , "bar");
+ test(PREP2 "C:\\foo\\bar" , "C:\\foo\\bar" , "bar");
+ test(PREP0 "C:\\foo\\bar\\", "C:\\foo\\bar\\" , NULL);
+ test(PREP1 "C:\\foo\\bar\\", "C:\\foo\\bar\\" , NULL);
+ test(PREP2 "C:\\foo\\bar\\", "C:\\foo\\bar\\" , NULL);
+ test(PREP1 "." , "" , NULL);
+ test(PREP2 "." , "." , ".");
+ test(PREP1 ".\\" , "" , NULL);
+ test(PREP2 ".\\" , ".\\" , NULL);
+ test(PREP1 ".." , "" , NULL);
+ test(PREP2 ".." , ".." , "..");
+ test(PREP1 "..\\" , "" , NULL);
+ test(PREP2 "..\\" , "..\\" , NULL);
+
+ // The following tests returns results based on current directory.
+ test(PREP0 "." , cd.szCD ,
cd.pszLastCDComponent);
+ test(PREP0 ".\\" , cd.szCDPlusSlash , NULL);
+ test(PREP0 ".." , cd.pszParentDir ,
cd.pszNextLastCDComponent);
+ test(PREP0 "..\\" , cd.pszParentDirPlusSlash, NULL);
+ test(cd.szCD , cd.szCD , cd.pszLastCDComponent);
+ test(cd.szCDPlusSlash , cd.szCDPlusSlash , NULL);
+
+#if 0
+ // This following test is "problematic", as it returns results based on
+ // what your CD on C: is, whether or not you actually run the program
+ // from C:. For that reason, it's currently disabled.
+ test(PREP0 "C:" , "C:\\" , NULL);
+#endif
+
+#if 0 // Disabled due to... see the comment inside the block.
+ {
+ char szExp[32];
+ BOOL bValid = FALSE;
+ char szPrepend[32];
+ szPrepend[0] = 0;
+ // Strictly speaking, this "Should Never Happen(tm)", calling
+ // RtlDosPathNameToNtPathName_U with a source already formed as
+ // a full NT name ("\??\"), why it's not the end of the world
+ // that this test is currently disabled.
+ //
+ // NOTE: _At least_ XP sp2 prepends this.
+ // Prepending curdrive like this is most likely a bug, but for
+ // compatibility it may become a requirement to "shim" this.
+ //
+ // Known operating systems prepending "Z:\??\" (assuming the
+ // process' CD is on the volume Z:):
+ // - XP sp2.
+ //
+ // Known operating systems not prepending:
+ // - Win7 64 (as 32-bit)
+ if (WinVerMaj == 5) {
+ sprintf(szPrepend, "%s\\??\\", cd.szCurDrive);
+ }
+
+ sprintf(szExp, "%s%s", szPrepend, "C:"); // Win7 64 (as 32-bit)
+ test("\\??\\C:", szExp, "C:");
+
+ sprintf(szExp, "%s%s", szPrepend, "C:\\");
+ test("\\??\\C:\\", szExp, NULL);
+ }
+#endif
+
+#ifndef COMPILE_AS_ROSTEST
+ return 0;
+#endif
+}
+
Propchange: trunk/rostests/apitests/ntdll/RtlDosPathNameToNtPathName_U.c
------------------------------------------------------------------------------
svn:eol-style = native