diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 3b0980d33cd..55729526837 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -443,7 +443,7 @@ @ stdcall RtlIntegerToUnicodeString(long long ptr) @ stdcall RtlIsDosDeviceName_U(wstr) RtlIsDosDeviceName_U @ stub RtlIsGenericTableEmpty -@ stub RtlIsNameLegalDOS8Dot3 +@ stdcall RtlIsNameLegalDOS8Dot3(ptr ptr ptr) @ stdcall RtlIsTextUnicode(ptr long ptr) @ stdcall -ret64 RtlLargeIntegerAdd(long long long long) @ stdcall -ret64 RtlLargeIntegerArithmeticShift(long long long) @@ -552,7 +552,7 @@ @ stdcall RtlUpcaseUnicodeChar(long) @ stdcall RtlUpcaseUnicodeString(ptr ptr long) @ stdcall RtlUpcaseUnicodeStringToAnsiString(ptr ptr long) -@ stub RtlUpcaseUnicodeStringToCountedOemString +@ stdcall RtlUpcaseUnicodeStringToCountedOemString(ptr ptr long) @ stdcall RtlUpcaseUnicodeStringToOemString(ptr ptr long) @ stub RtlUpcaseUnicodeToCustomCPN @ stdcall RtlUpcaseUnicodeToMultiByteN(ptr long ptr ptr long) diff --git a/dlls/ntdll/path.c b/dlls/ntdll/path.c index 6440499a30a..535ba636580 100644 --- a/dlls/ntdll/path.c +++ b/dlls/ntdll/path.c @@ -1,7 +1,8 @@ /* * Ntdll path functions * - * Copyright 2002 Alexandre Julliard + * Copyright 2002, 2003 Alexandre Julliard + * Copyright 2003 Eric Pouech * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -22,6 +23,9 @@ #include "winternl.h" #include "wine/unicode.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(file); #define IS_SEPARATOR(ch) ((ch) == '\\' || (ch) == '/') @@ -123,3 +127,73 @@ ULONG WINAPI RtlIsDosDeviceName_U( PCWSTR dos_name ) } return 0; } + + +/****************************************************************** + * RtlIsNameLegalDOS8Dot3 (NTDLL.@) + * + * Returns TRUE iff unicode is a valid DOS (8+3) name. + * If the name is valid, oem gets filled with the corresponding OEM string + * spaces is set to TRUE if unicode contains spaces + */ +BOOLEAN WINAPI RtlIsNameLegalDOS8Dot3( const UNICODE_STRING *unicode, + OEM_STRING *oem, BOOLEAN *spaces ) +{ + int dot = -1; + unsigned int i; + char buffer[12]; + OEM_STRING oem_str; + BOOLEAN got_space = FALSE; + + if (!oem) + { + oem_str.Length = sizeof(buffer); + oem_str.MaximumLength = sizeof(buffer); + oem_str.Buffer = buffer; + oem = &oem_str; + } + if (RtlUpcaseUnicodeStringToCountedOemString( oem, unicode, FALSE ) != STATUS_SUCCESS) + return FALSE; + + if (oem->Length > 12) return FALSE; + + /* a starting . is invalid, except for . and .. */ + if (oem->Buffer[0] == '.') + { + if (oem->Length != 1 && (oem->Length != 2 || oem->Buffer[1] != '.')) return FALSE; + if (spaces) *spaces = FALSE; + return TRUE; + } + + for (i = 0; i < oem->Length; i++) + { + switch (oem->Buffer[i]) + { + case ' ': + /* leading/trailing spaces not allowed */ + if (!i || i == oem->Length-1 || oem->Buffer[i+1] == '.') return FALSE; + got_space = TRUE; + break; + case '.': + if (dot != -1) return FALSE; + dot = i; + break; + default: + /* FIXME: check for invalid chars */ + break; + } + } + /* check file part is shorter than 8, extension shorter than 3 + * dot cannot be last in string + */ + if (dot == -1) + { + if (oem->Length > 8) return FALSE; + } + else + { + if (dot > 8 || (oem->Length - dot > 4) || dot == oem->Length - 1) return FALSE; + } + if (spaces) *spaces = got_space; + return TRUE; +} diff --git a/dlls/ntdll/rtlstr.c b/dlls/ntdll/rtlstr.c index 88d7e042625..f8e1b1cad5b 100644 --- a/dlls/ntdll/rtlstr.c +++ b/dlls/ntdll/rtlstr.c @@ -835,6 +835,46 @@ NTSTATUS WINAPI RtlUpcaseUnicodeStringToOemString( STRING *dst, } +/************************************************************************** + * RtlUpcaseUnicodeStringToCountedOemString (NTDLL.@) + * + * NOTES + * Same as RtlUpcaseUnicodeStringToOemString but doesn't write terminating null + */ +NTSTATUS WINAPI RtlUpcaseUnicodeStringToCountedOemString( STRING *oem, + const UNICODE_STRING *uni, + BOOLEAN doalloc ) +{ + NTSTATUS ret; + UNICODE_STRING upcase; + + if (!(ret = RtlUpcaseUnicodeString( &upcase, uni, TRUE ))) + { + DWORD len = RtlUnicodeStringToOemSize( &upcase ) - 1; + oem->Length = len; + if (doalloc) + { + oem->MaximumLength = len; + if (!(oem->Buffer = RtlAllocateHeap( ntdll_get_process_heap(), 0, len ))) + { + ret = STATUS_NO_MEMORY; + goto done; + } + } + else if (oem->MaximumLength < len) + { + ret = STATUS_BUFFER_OVERFLOW; + oem->Length = oem->MaximumLength; + if (!oem->MaximumLength) goto done; + } + RtlUnicodeToOemN( oem->Buffer, oem->Length, NULL, upcase.Buffer, upcase.Length ); + done: + RtlFreeUnicodeString( &upcase ); + } + return ret; +} + + /************************************************************************** * RtlUpcaseUnicodeToMultiByteN (NTDLL.@) */ diff --git a/dlls/ntdll/tests/path.c b/dlls/ntdll/tests/path.c index 6641d2d4dc0..383b8f5f290 100644 --- a/dlls/ntdll/tests/path.c +++ b/dlls/ntdll/tests/path.c @@ -26,6 +26,8 @@ static NTSTATUS (WINAPI *pRtlMultiByteToUnicodeN)( LPWSTR dst, DWORD dstlen, LPD LPCSTR src, DWORD srclen ); static UINT (WINAPI *pRtlDetermineDosPathNameType_U)( PCWSTR path ); static ULONG (WINAPI *pRtlIsDosDeviceName_U)( PCWSTR dos_name ); +static NTSTATUS (WINAPI *pRtlOemStringToUnicodeString)(UNICODE_STRING *, const STRING *, BOOLEAN ); +static BOOLEAN (WINAPI *pRtlIsNameLegalDOS8Dot3)(const UNICODE_STRING*,POEM_STRING,PBOOLEAN); static void test_RtlDetermineDosPathNameType(void) { @@ -145,6 +147,75 @@ static void test_RtlIsDosDeviceName(void) } } +static void test_RtlIsNameLegalDOS8Dot3(void) +{ + struct test + { + char *path; + BOOLEAN result; + BOOLEAN spaces; + }; + + static const struct test tests[] = + { + { "12345678", TRUE, FALSE }, + { "123 5678", TRUE, TRUE }, + { "12345678.", FALSE, 2 /*not set*/ }, + { "1234 678.", FALSE, 2 /*not set*/ }, + { "12345678.a", TRUE, FALSE }, + { "12345678.a ", FALSE, 2 /*not set*/ }, + { "12345678.a c", TRUE, TRUE }, + { " 2345678.a ", FALSE, 2 /*not set*/ }, + { "1 345678.abc", TRUE, TRUE }, + { "1 8.a c", TRUE, TRUE }, + { "1 3 5 7 .abc", FALSE, 2 /*not set*/ }, + { "12345678. c", TRUE, TRUE }, + { "123456789.a", FALSE, 2 /*not set*/ }, + { "12345.abcd", FALSE, 2 /*not set*/ }, + { "12345.ab d", FALSE, 2 /*not set*/ }, + { ".abc", FALSE, 2 /*not set*/ }, + { "12.abc.d", FALSE, 2 /*not set*/ }, + { ".", TRUE, FALSE }, + { "..", TRUE, FALSE }, + { "...", FALSE, 2 /*not set*/ }, + { "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", FALSE, 2 /*not set*/ }, + { NULL, 0 } + }; + + const struct test *test; + UNICODE_STRING ustr; + OEM_STRING oem, oem_ret; + WCHAR buffer[200]; + char buff2[12]; + BOOLEAN ret, spaces; + + ustr.MaximumLength = sizeof(buffer); + ustr.Buffer = buffer; + for (test = tests; test->path; test++) + { + oem.Buffer = test->path; + oem.Length = strlen(test->path); + oem.MaximumLength = oem.Length + 1; + pRtlOemStringToUnicodeString( &ustr, &oem, FALSE ); + spaces = 2; + oem_ret.Length = oem_ret.MaximumLength = sizeof(buff2); + oem_ret.Buffer = buff2; + ret = pRtlIsNameLegalDOS8Dot3( &ustr, &oem_ret, &spaces ); + ok( ret == test->result, "Wrong result %d/%d for '%s'", ret, test->result, test->path ); + ok( spaces == test->spaces, "Wrong spaces value %d/%d for '%s'", spaces, test->spaces, test->path ); + if (strlen(test->path) <= 12) + { + char str[13]; + int i; + strcpy( str, test->path ); + for (i = 0; str[i]; i++) str[i] = toupper(str[i]); + ok( oem_ret.Length == strlen(test->path), "Wrong length %d/%d for '%s'", + oem_ret.Length, strlen(test->path), test->path ); + ok( !memcmp( oem_ret.Buffer, str, oem_ret.Length ), + "Wrong string '%.*s'/'%s'", oem_ret.Length, oem_ret.Buffer, str ); + } + } +} START_TEST(path) @@ -153,6 +224,9 @@ START_TEST(path) pRtlMultiByteToUnicodeN = (void *)GetProcAddress(mod,"RtlMultiByteToUnicodeN"); pRtlDetermineDosPathNameType_U = (void *)GetProcAddress(mod,"RtlDetermineDosPathNameType_U"); pRtlIsDosDeviceName_U = (void *)GetProcAddress(mod,"RtlIsDosDeviceName_U"); + pRtlOemStringToUnicodeString = (void *)GetProcAddress(mod,"RtlOemStringToUnicodeString"); + pRtlIsNameLegalDOS8Dot3 = (void *)GetProcAddress(mod,"RtlIsNameLegalDOS8Dot3"); test_RtlDetermineDosPathNameType(); test_RtlIsDosDeviceName(); + test_RtlIsNameLegalDOS8Dot3(); } diff --git a/include/winternl.h b/include/winternl.h index 02325378784..97c4d5c186b 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -1021,7 +1021,7 @@ 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); +BOOLEAN WINAPI RtlIsNameLegalDOS8Dot3(const UNICODE_STRING*,POEM_STRING,PBOOLEAN); DWORD WINAPI RtlIsTextUnicode(LPVOID,DWORD,DWORD *); LONGLONG WINAPI RtlLargeIntegerAdd(LONGLONG,LONGLONG); @@ -1109,6 +1109,7 @@ void WINAPI RtlUnwindEx(FRAME_POINTERS,PVOID,PEXCEPTION_RECORD,PVOID,PCONTE WCHAR WINAPI RtlUpcaseUnicodeChar(WCHAR); NTSTATUS WINAPI RtlUpcaseUnicodeString(UNICODE_STRING*,const UNICODE_STRING *,BOOLEAN); NTSTATUS WINAPI RtlUpcaseUnicodeStringToAnsiString(STRING*,const UNICODE_STRING*,BOOLEAN); +NTSTATUS WINAPI RtlUpcaseUnicodeStringToCountedOemString(STRING*,const UNICODE_STRING*,BOOLEAN); NTSTATUS WINAPI RtlUpcaseUnicodeStringToOemString(STRING*,const UNICODE_STRING*,BOOLEAN); NTSTATUS WINAPI RtlUpcaseUnicodeToMultiByteN(LPSTR,DWORD,LPDWORD,LPCWSTR,DWORD); NTSTATUS WINAPI RtlUpcaseUnicodeToOemN(LPSTR,DWORD,LPDWORD,LPCWSTR,DWORD);