From aa94a5ad1ae41932d637f7e2c8567d916e2aceb6 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Sat, 12 Apr 2003 00:10:13 +0000 Subject: [PATCH] Implemented RtlDetermineDosPathNameType_U and RtlIsDosDeviceName_U. --- dlls/ntdll/Makefile.in | 1 + dlls/ntdll/ntdll.spec | 4 +- dlls/ntdll/path.c | 125 ++++++++++++++++++++++++++++++++++ dlls/ntdll/tests/.cvsignore | 1 + dlls/ntdll/tests/Makefile.in | 1 + dlls/ntdll/tests/path.c | 158 +++++++++++++++++++++++++++++++++++++++++++ include/winternl.h | 18 ++++- 7 files changed, 305 insertions(+), 3 deletions(-) create mode 100644 dlls/ntdll/path.c create mode 100644 dlls/ntdll/tests/path.c diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in index 5353280e49a..f27cecf7906 100644 --- a/dlls/ntdll/Makefile.in +++ b/dlls/ntdll/Makefile.in @@ -83,6 +83,7 @@ C_SRCS = \ misc.c \ nt.c \ om.c \ + path.c \ reg.c \ rtl.c \ rtlstr.c \ diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 36f301eb886..3b0980d33cd 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -347,7 +347,7 @@ @ stdcall RtlDestroyHeap(long) @ stub RtlDestroyProcessParameters @ stub RtlDestroyQueryDebugBuffer -@ stub RtlDetermineDosPathNameType_U +@ stdcall RtlDetermineDosPathNameType_U(wstr) RtlDetermineDosPathNameType_U @ stub RtlDoesFileExists_U @ stdcall RtlDosPathNameToNtPathName_U(ptr ptr long long) @ stub RtlDosSearchPath_U @@ -441,7 +441,7 @@ @ stdcall RtlInt64ToUnicodeString(long long long ptr) @ stdcall RtlIntegerToChar(long long long ptr) @ stdcall RtlIntegerToUnicodeString(long long ptr) -@ stub RtlIsDosDeviceName_U +@ stdcall RtlIsDosDeviceName_U(wstr) RtlIsDosDeviceName_U @ stub RtlIsGenericTableEmpty @ stub RtlIsNameLegalDOS8Dot3 @ stdcall RtlIsTextUnicode(ptr long ptr) diff --git a/dlls/ntdll/path.c b/dlls/ntdll/path.c new file mode 100644 index 00000000000..6440499a30a --- /dev/null +++ b/dlls/ntdll/path.c @@ -0,0 +1,125 @@ +/* + * Ntdll path functions + * + * Copyright 2002 Alexandre Julliard + * + * 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 "config.h" + +#include "winternl.h" +#include "wine/unicode.h" + +#define IS_SEPARATOR(ch) ((ch) == '\\' || (ch) == '/') + +/*********************************************************************** + * RtlDetermineDosPathNameType_U (NTDLL.@) + */ +DOS_PATHNAME_TYPE WINAPI RtlDetermineDosPathNameType_U( PCWSTR path ) +{ + if (IS_SEPARATOR(path[0])) + { + if (!IS_SEPARATOR(path[1])) return ABSOLUTE_PATH; /* "/foo" */ + if (path[2] != '.') return UNC_PATH; /* "//foo" */ + if (IS_SEPARATOR(path[3])) return DEVICE_PATH; /* "//./foo" */ + if (path[3]) return UNC_PATH; /* "//.foo" */ + return UNC_DOT_PATH; /* "//." */ + } + else + { + if (!path[0] || path[1] != ':') return RELATIVE_PATH; /* "foo" */ + if (IS_SEPARATOR(path[2])) return ABSOLUTE_DRIVE_PATH; /* "c:/foo" */ + return RELATIVE_DRIVE_PATH; /* "c:foo" */ + } +} + + +/*********************************************************************** + * RtlIsDosDeviceName_U (NTDLL.@) + * + * Check if the given DOS path contains a DOS device name. + * + * Returns the length of the device name in the low word and its + * position in the high word (both in bytes, not WCHARs), or 0 if no + * device name is found. + */ +ULONG WINAPI RtlIsDosDeviceName_U( PCWSTR dos_name ) +{ + static const WCHAR consoleW[] = {'\\','\\','.','\\','C','O','N',0}; + static const WCHAR auxW[3] = {'A','U','X'}; + static const WCHAR comW[3] = {'C','O','M'}; + static const WCHAR conW[3] = {'C','O','N'}; + static const WCHAR lptW[3] = {'L','P','T'}; + static const WCHAR nulW[3] = {'N','U','L'}; + static const WCHAR prnW[3] = {'P','R','N'}; + + const WCHAR *start, *end, *p; + + switch(RtlDetermineDosPathNameType_U( dos_name )) + { + case INVALID_PATH: + case UNC_PATH: + return 0; + case DEVICE_PATH: + if (!strcmpiW( dos_name, consoleW )) + return MAKELONG( sizeof(conW), 4 * sizeof(WCHAR) ); /* 4 is length of \\.\ prefix */ + return 0; + default: + break; + } + + end = dos_name + strlenW(dos_name) - 1; + if (end >= dos_name && *end == ':') end--; /* remove trailing ':' */ + + /* find start of file name */ + for (start = end; start >= dos_name; start--) + { + if (IS_SEPARATOR(start[0])) break; + /* check for ':' but ignore if before extension (for things like NUL:.txt) */ + if (start[0] == ':' && start[1] != '.') break; + } + start++; + + /* remove extension */ + if ((p = strchrW( start, '.' ))) + { + end = p - 1; + if (end >= dos_name && *end == ':') end--; /* remove trailing ':' before extension */ + } + else + { + /* no extension, remove trailing spaces */ + while (end >= dos_name && *end == ' ') end--; + } + + /* now we have a potential device name between start and end, check it */ + switch(end - start + 1) + { + case 3: + if (strncmpiW( start, auxW, 3 ) && + strncmpiW( start, conW, 3 ) && + strncmpiW( start, nulW, 3 ) && + strncmpiW( start, prnW, 3 )) break; + return MAKELONG( 3 * sizeof(WCHAR), (start - dos_name) * sizeof(WCHAR) ); + case 4: + if (strncmpiW( start, comW, 3 ) && strncmpiW( start, lptW, 3 )) break; + if (*end <= '0' || *end > '9') break; + return MAKELONG( 4 * sizeof(WCHAR), (start - dos_name) * sizeof(WCHAR) ); + default: /* can't match anything */ + break; + } + return 0; +} diff --git a/dlls/ntdll/tests/.cvsignore b/dlls/ntdll/tests/.cvsignore index aea4bfbd6d4..ce2607c848c 100644 --- a/dlls/ntdll/tests/.cvsignore +++ b/dlls/ntdll/tests/.cvsignore @@ -3,6 +3,7 @@ error.ok generated.ok large_int.ok ntdll_test.exe.spec.c +path.ok rtl.ok rtlbitmap.ok rtlstr.ok diff --git a/dlls/ntdll/tests/Makefile.in b/dlls/ntdll/tests/Makefile.in index 32ee55ac7c7..e226ac7e705 100644 --- a/dlls/ntdll/tests/Makefile.in +++ b/dlls/ntdll/tests/Makefile.in @@ -9,6 +9,7 @@ CTESTS = \ error.c \ generated.c \ large_int.c \ + path.c \ rtl.c \ rtlbitmap.c \ rtlstr.c \ diff --git a/dlls/ntdll/tests/path.c b/dlls/ntdll/tests/path.c new file mode 100644 index 00000000000..6641d2d4dc0 --- /dev/null +++ b/dlls/ntdll/tests/path.c @@ -0,0 +1,158 @@ +/* + * Unit test suite for ntdll path functions + * + * Copyright 2002 Alexandre Julliard + * + * 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 "wine/test.h" +#include "winnt.h" +#include "winternl.h" + +static NTSTATUS (WINAPI *pRtlMultiByteToUnicodeN)( LPWSTR dst, DWORD dstlen, LPDWORD reslen, + LPCSTR src, DWORD srclen ); +static UINT (WINAPI *pRtlDetermineDosPathNameType_U)( PCWSTR path ); +static ULONG (WINAPI *pRtlIsDosDeviceName_U)( PCWSTR dos_name ); + +static void test_RtlDetermineDosPathNameType(void) +{ + struct test + { + const char *path; + int ret; + }; + + static const struct test tests[] = + { + { "\\\\foo", 1 }, + { "//foo", 1 }, + { "\\/foo", 1 }, + { "/\\foo", 1 }, + { "\\\\", 1 }, + { "//", 1 }, + { "c:\\foo", 2 }, + { "c:/foo", 2 }, + { "c://foo", 2 }, + { "c:\\", 2 }, + { "c:/", 2 }, + { "c:foo", 3 }, + { "c:f\\oo", 3 }, + { "c:foo/bar", 3 }, + { "\\foo", 4 }, + { "/foo", 4 }, + { "\\", 4 }, + { "/", 4 }, + { "foo", 5 }, + { "", 5 }, + { "\0:foo", 5 }, + { "\\\\.\\foo", 6 }, + { "//./foo", 6 }, + { "/\\./foo", 6 }, + { "\\\\.foo", 1 }, + { "//.foo", 1 }, + { "\\\\.", 7 }, + { "//.", 7 }, + { NULL, 0 } + }; + + const struct test *test; + WCHAR buffer[MAX_PATH]; + UINT ret; + + for (test = tests; test->path; test++) + { + pRtlMultiByteToUnicodeN( buffer, sizeof(buffer), NULL, test->path, strlen(test->path)+1 ); + ret = pRtlDetermineDosPathNameType_U( buffer ); + ok( ret == test->ret, "Wrong result %d/%d for %s", ret, test->ret, test->path ); + } +} + + +static void test_RtlIsDosDeviceName(void) +{ + struct test + { + const char *path; + WORD pos; + WORD len; + }; + + static const struct test tests[] = + { + { "\\\\.\\CON", 8, 6 }, + { "\\\\.\\con", 8, 6 }, + { "\\\\.\\CON2", 0, 0 }, + { "", 0, 0 }, + { "\\\\foo\\nul", 0, 0 }, + { "c:\\nul:", 6, 6 }, + { "c:\\nul::", 0, 0 }, + { "c:prn ", 4, 6 }, + { "c:prn.......", 4, 6 }, + { "c:prn... ...", 4, 6 }, + { "c:NUL .... ", 0, 0 }, + { "c: . . .", 0, 0 }, + { "c:", 0, 0 }, + { " . . . :", 0, 0 }, + { ":", 0, 0 }, + { "c:nul. . . :", 4, 6 }, + { "c:nul . . :", 0, 0 }, + { "c:nul0", 0, 0 }, + { "c:prn:aaa", 0, 0 }, + { "c:PRN:.txt", 4, 6 }, + { "c:aux:.txt...", 4, 6 }, + { "c:prn:.txt:", 4, 6 }, + { "c:nul:aaa", 0, 0 }, + { "con:", 0, 6 }, + { "lpt1:", 0, 8 }, + { "c:com5:", 4, 8 }, + { "CoM4:", 0, 8 }, + { "lpt9:", 0, 8 }, + { "c:\\lpt0.txt", 0, 0 }, + { "c:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\\nul.txt", 1000, 6 }, + { NULL, 0 } + }; + + const struct test *test; + WCHAR buffer[2000]; + ULONG ret; + + for (test = tests; test->path; test++) + { + pRtlMultiByteToUnicodeN( buffer, sizeof(buffer), NULL, test->path, strlen(test->path)+1 ); + ret = pRtlIsDosDeviceName_U( buffer ); + ok( ret == MAKELONG( test->len, test->pos ), + "Wrong result (%d,%d)/(%d,%d) for %s", + HIWORD(ret), LOWORD(ret), test->pos, test->len, test->path ); + } +} + + + +START_TEST(path) +{ + HMODULE mod = GetModuleHandleA("ntdll.dll"); + pRtlMultiByteToUnicodeN = (void *)GetProcAddress(mod,"RtlMultiByteToUnicodeN"); + pRtlDetermineDosPathNameType_U = (void *)GetProcAddress(mod,"RtlDetermineDosPathNameType_U"); + pRtlIsDosDeviceName_U = (void *)GetProcAddress(mod,"RtlIsDosDeviceName_U"); + test_RtlDetermineDosPathNameType(); + test_RtlIsDosDeviceName(); +} diff --git a/include/winternl.h b/include/winternl.h index 5a3ddb42a59..02325378784 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -327,6 +327,19 @@ typedef enum MemoryBasicInformation = 0 } MEMORY_INFORMATION_CLASS; +/* return type of RtlDetermineDosPathNameType_U (FIXME: not the correct names) */ +typedef enum +{ + INVALID_PATH = 0, + UNC_PATH, /* "//foo" */ + ABSOLUTE_DRIVE_PATH, /* "c:/foo" */ + RELATIVE_DRIVE_PATH, /* "c:foo" */ + ABSOLUTE_PATH, /* "/foo" */ + RELATIVE_PATH, /* "foo" */ + DEVICE_PATH, /* "//./foo" */ + UNC_DOT_PATH /* "//." */ +} DOS_PATHNAME_TYPE; + /*********************************************************************** * IA64 specific types and data structures */ @@ -935,6 +948,7 @@ void WINAPI RtlDeleteResource(LPRTL_RWLOCK); DWORD WINAPI RtlDeleteSecurityObject(DWORD); DWORD WINAPI RtlDestroyEnvironment(DWORD); HANDLE WINAPI RtlDestroyHeap(HANDLE); +DOS_PATHNAME_TYPE WINAPI RtlDetermineDosPathNameType_U(PCWSTR); BOOLEAN WINAPI RtlDosPathNameToNtPathName_U(LPWSTR,PUNICODE_STRING,DWORD,DWORD); WCHAR WINAPI RtlDowncaseUnicodeChar(WCHAR); NTSTATUS WINAPI RtlDowncaseUnicodeString(UNICODE_STRING*,const UNICODE_STRING*,BOOLEAN); @@ -979,8 +993,9 @@ DWORD WINAPI RtlFreeSid(PSID); void WINAPI RtlFreeUnicodeString(PUNICODE_STRING); DWORD WINAPI RtlGetAce(PACL,DWORD,LPVOID *); -NTSTATUS WINAPI RtlGetDaclSecurityDescriptor(PSECURITY_DESCRIPTOR,PBOOLEAN,PACL *,PBOOLEAN); NTSTATUS WINAPI RtlGetControlSecurityDescriptor(PSECURITY_DESCRIPTOR, PSECURITY_DESCRIPTOR_CONTROL,LPDWORD); +NTSTATUS WINAPI RtlGetDaclSecurityDescriptor(PSECURITY_DESCRIPTOR,PBOOLEAN,PACL *,PBOOLEAN); +ULONG WINAPI RtlGetFullPathName_U(PCWSTR,ULONG,PWSTR,PWSTR*); NTSTATUS WINAPI RtlGetGroupSecurityDescriptor(PSECURITY_DESCRIPTOR,PSID *,PBOOLEAN); BOOLEAN WINAPI RtlGetNtProductType(LPDWORD); NTSTATUS WINAPI RtlGetOwnerSecurityDescriptor(PSECURITY_DESCRIPTOR,PSID *,PBOOLEAN); @@ -1005,6 +1020,7 @@ BOOL WINAPI RtlInitializeSid(PSID,PSID_IDENTIFIER_AUTHORITY,BYTE); NTSTATUS WINAPI RtlInt64ToUnicodeString(ULONGLONG,ULONG,UNICODE_STRING *); NTSTATUS WINAPI RtlIntegerToChar(ULONG,ULONG,ULONG,PCHAR); NTSTATUS WINAPI RtlIntegerToUnicodeString(ULONG,ULONG,UNICODE_STRING *); +ULONG WINAPI RtlIsDosDeviceName_U(PCWSTR); BOOLEAN WINAPI RtlIsNameLegalDOS8Dot3(PUNICODE_STRING,POEM_STRING,PBOOLEAN); DWORD WINAPI RtlIsTextUnicode(LPVOID,DWORD,DWORD *); -- 2.11.4.GIT