Implemented RtlIsNameLegalDOS8Dot3 (based on a patch by Eric Pouech).
Implemented RtlUpcaseUnicodeStringToCountedOemString.

diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index 3b0980d..5572952 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 6440499..535ba63 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 @@
     }
     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 88d7e04..f8e1b1c 100644
--- a/dlls/ntdll/rtlstr.c
+++ b/dlls/ntdll/rtlstr.c
@@ -836,6 +836,46 @@
 
 
 /**************************************************************************
+ *	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.@)
  */
 NTSTATUS WINAPI RtlUpcaseUnicodeToMultiByteN( LPSTR dst, DWORD dstlen, LPDWORD reslen,
diff --git a/dlls/ntdll/tests/path.c b/dlls/ntdll/tests/path.c
index 6641d2d..383b8f5 100644
--- a/dlls/ntdll/tests/path.c
+++ b/dlls/ntdll/tests/path.c
@@ -26,6 +26,8 @@
                                                    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_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 @@
     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 0232537..97c4d5c 100644
--- a/include/winternl.h
+++ b/include/winternl.h
@@ -1021,7 +1021,7 @@
 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 @@
 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);