ntdll: Make NtGetNlsSectionPtr() into a proper Nt syscall.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2020-10-15 20:17:46 +02:00
parent 892780a5d2
commit 54c31d5332
4 changed files with 151 additions and 202 deletions

View file

@ -4131,7 +4131,7 @@ static void test_GetCPInfo(void)
status = pNtGetNlsSectionPtr( i, 9999, NULL, &ptr, &size );
switch (i)
{
case 9: /* unknown */
case 9: /* sortkeys */
case 13: /* unknown */
ok( status == STATUS_INVALID_PARAMETER_1 || status == STATUS_INVALID_PARAMETER_3, /* vista */
"%u: failed %x\n", i, status );
@ -4160,9 +4160,9 @@ static void test_GetCPInfo(void)
status = pNtGetNlsSectionPtr( 10, 0, NULL, &ptr2, &size );
ok( ptr != ptr2, "got same pointer\n" );
ret = UnmapViewOfFile( ptr );
todo_wine ok( ret, "UnmapViewOfFile failed err %u\n", GetLastError() );
ok( ret, "UnmapViewOfFile failed err %u\n", GetLastError() );
ret = UnmapViewOfFile( ptr2 );
todo_wine ok( ret, "UnmapViewOfFile failed err %u\n", GetLastError() );
ok( ret, "UnmapViewOfFile failed err %u\n", GetLastError() );
}
/* codepage tables */
@ -4182,7 +4182,7 @@ static void test_GetCPInfo(void)
ok( !table.DBCSCodePage, "wrong dbcs %u\n", table.DBCSCodePage );
}
ret = UnmapViewOfFile( ptr );
todo_wine ok( ret, "UnmapViewOfFile failed err %u\n", GetLastError() );
ok( ret, "UnmapViewOfFile failed err %u\n", GetLastError() );
status = pNtGetNlsSectionPtr( 11, 936, NULL, &ptr, &size );
ok( !status, "failed %x\n", status );
@ -4220,7 +4220,7 @@ static void test_GetCPInfo(void)
}
}
ret = UnmapViewOfFile( ptr );
todo_wine ok( ret, "UnmapViewOfFile failed err %u\n", GetLastError() );
ok( ret, "UnmapViewOfFile failed err %u\n", GetLastError() );
/* normalization tables */
@ -4238,7 +4238,7 @@ static void test_GetCPInfo(void)
if (status) break;
ok( size > 0x8000 && size <= 0x30000 , "wrong size %lx\n", size );
ret = UnmapViewOfFile( ptr );
todo_wine ok( ret, "UnmapViewOfFile failed err %u\n", GetLastError() );
ok( ret, "UnmapViewOfFile failed err %u\n", GetLastError() );
break;
default:
ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "%u: failed %x\n", i, status );

View file

@ -228,13 +228,13 @@ static NTSTATUS load_norm_table( ULONG form, const struct norm_table **info )
}
if (InterlockedCompareExchangePointer( (void **)&norm_tables[form], data, NULL ))
RtlFreeHeap( GetProcessHeap(), 0, data );
NtUnmapViewOfSection( GetCurrentProcess(), data );
}
*info = norm_tables[form];
return STATUS_SUCCESS;
invalid:
RtlFreeHeap( GetProcessHeap(), 0, data );
NtUnmapViewOfSection( GetCurrentProcess(), data );
return STATUS_INVALID_PARAMETER;
}
@ -534,156 +534,6 @@ static unsigned int compose_string( const struct norm_table *info, WCHAR *str, u
}
static NTSTATUS open_nls_data_file( ULONG type, ULONG id, HANDLE *file )
{
static const WCHAR pathfmtW[] = {'\\','?','?','\\','%','s','%','s',0};
static const WCHAR keyfmtW[] =
{'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\','S','y','s','t','e','m','\\',
'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
'C','o','n','t','r','o','l','\\','N','l','s','\\','%','s',0};
static const WCHAR sortdirW[] = {'C',':','\\','w','i','n','d','o','w','s','\\',
'g','l','o','b','a','l','i','z','a','t','i','o','n','\\',
's','o','r','t','i','n','g','\\',0};
static const WCHAR cpW[] = {'C','o','d','e','p','a','g','e',0};
static const WCHAR normW[] = {'N','o','r','m','a','l','i','z','a','t','i','o','n',0};
static const WCHAR langW[] = {'L','a','n','g','u','a','g','e',0};
static const WCHAR cpfmtW[] = {'%','u',0};
static const WCHAR normfmtW[] = {'%','x',0};
static const WCHAR langfmtW[] = {'%','0','4','x',0};
static const WCHAR winedatadirW[] = {'W','I','N','E','D','A','T','A','D','I','R',0};
static const WCHAR winebuilddirW[] = {'W','I','N','E','B','U','I','L','D','D','I','R',0};
static const WCHAR dataprefixW[] = {'\\','n','l','s','\\',0};
static const WCHAR cpdefaultW[] = {'c','_','%','0','3','d','.','n','l','s',0};
static const WCHAR intlW[] = {'l','_','i','n','t','l','.','n','l','s',0};
static const WCHAR normnfcW[] = {'n','o','r','m','n','f','c','.','n','l','s',0};
static const WCHAR normnfdW[] = {'n','o','r','m','n','f','d','.','n','l','s',0};
static const WCHAR normnfkcW[] = {'n','o','r','m','n','f','k','c','.','n','l','s',0};
static const WCHAR normnfkdW[] = {'n','o','r','m','n','f','k','d','.','n','l','s',0};
static const WCHAR normidnaW[] = {'n','o','r','m','i','d','n','a','.','n','l','s',0};
static const WCHAR sortkeysW[] = {'s','o','r','t','d','e','f','a','u','l','t','.','n','l','s',0};
DWORD size;
HANDLE handle;
NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND;
IO_STATUS_BLOCK io;
OBJECT_ATTRIBUTES attr;
UNICODE_STRING nameW, valueW;
WCHAR buffer[MAX_PATH], value[10];
const WCHAR *name = NULL, *dir = system_dir;
KEY_VALUE_PARTIAL_INFORMATION *info;
/* get filename from registry */
switch (type)
{
case NLS_SECTION_SORTKEYS:
if (id) return STATUS_INVALID_PARAMETER_1;
buffer[0] = 0;
break;
case NLS_SECTION_CASEMAP:
if (id) return STATUS_UNSUCCESSFUL;
swprintf( buffer, ARRAY_SIZE(buffer), keyfmtW, langW );
swprintf( value, ARRAY_SIZE(value), langfmtW, LANGIDFROMLCID(system_lcid) );
break;
case NLS_SECTION_CODEPAGE:
swprintf( buffer, ARRAY_SIZE(buffer), keyfmtW, cpW );
swprintf( value, ARRAY_SIZE(value), cpfmtW, id );
break;
case NLS_SECTION_NORMALIZE:
swprintf( buffer, ARRAY_SIZE(buffer), keyfmtW, normW );
swprintf( value, ARRAY_SIZE(value), normfmtW, id );
break;
default:
return STATUS_INVALID_PARAMETER_1;
}
if (buffer[0])
{
RtlInitUnicodeString( &nameW, buffer );
RtlInitUnicodeString( &valueW, value );
InitializeObjectAttributes( &attr, &nameW, 0, 0, NULL );
if (!(status = NtOpenKey( &handle, KEY_READ, &attr )))
{
info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
size = sizeof(buffer) - sizeof(WCHAR);
if (!(status = NtQueryValueKey( handle, &valueW, KeyValuePartialInformation, info, size, &size )))
{
((WCHAR *)info->Data)[info->DataLength / sizeof(WCHAR)] = 0;
name = (WCHAR *)info->Data;
}
NtClose( handle );
}
}
if (!name || !*name) /* otherwise some hardcoded defaults */
{
switch (type)
{
case NLS_SECTION_SORTKEYS:
name = sortkeysW;
dir = sortdirW;
break;
case NLS_SECTION_CASEMAP:
name = intlW;
break;
case NLS_SECTION_CODEPAGE:
swprintf( buffer, ARRAY_SIZE(buffer), cpdefaultW, id );
name = buffer;
break;
case NLS_SECTION_NORMALIZE:
switch (id)
{
case NormalizationC: name = normnfcW; break;
case NormalizationD: name = normnfdW; break;
case NormalizationKC: name = normnfkcW; break;
case NormalizationKD: name = normnfkdW; break;
case 13: name = normidnaW; break;
}
break;
}
if (!name) return status;
}
/* try to open file in system dir */
valueW.MaximumLength = (wcslen(name) + wcslen(dir) + 5) * sizeof(WCHAR);
if (!(valueW.Buffer = RtlAllocateHeap( GetProcessHeap(), 0, valueW.MaximumLength )))
return STATUS_NO_MEMORY;
valueW.Length = swprintf( valueW.Buffer, valueW.MaximumLength/sizeof(WCHAR),
pathfmtW, dir, name ) * sizeof(WCHAR);
InitializeObjectAttributes( &attr, &valueW, 0, 0, NULL );
status = NtOpenFile( file, GENERIC_READ, &attr, &io, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_ALERT );
if (!status) TRACE( "found %s\n", debugstr_w( valueW.Buffer ));
RtlFreeUnicodeString( &valueW );
if (status != STATUS_OBJECT_NAME_NOT_FOUND && status != STATUS_OBJECT_PATH_NOT_FOUND) return status;
/* not found, try in build or data dir */
RtlInitUnicodeString( &nameW, winebuilddirW );
valueW.MaximumLength = 0;
if (RtlQueryEnvironmentVariable_U( NULL, &nameW, &valueW ) != STATUS_BUFFER_TOO_SMALL)
{
RtlInitUnicodeString( &nameW, winedatadirW );
if (RtlQueryEnvironmentVariable_U( NULL, &nameW, &valueW ) != STATUS_BUFFER_TOO_SMALL)
return status;
}
valueW.MaximumLength = valueW.Length + sizeof(dataprefixW) + wcslen(name) * sizeof(WCHAR);
if (!(valueW.Buffer = RtlAllocateHeap( GetProcessHeap(), 0, valueW.MaximumLength )))
return STATUS_NO_MEMORY;
if (!RtlQueryEnvironmentVariable_U( NULL, &nameW, &valueW ))
{
wcscat( valueW.Buffer, dataprefixW );
wcscat( valueW.Buffer, name );
valueW.Length = wcslen(valueW.Buffer) * sizeof(WCHAR);
InitializeObjectAttributes( &attr, &valueW, 0, 0, NULL );
status = NtOpenFile( file, GENERIC_READ, &attr, &io, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_ALERT );
if (!status) TRACE( "found %s\n", debugstr_w( valueW.Buffer ));
}
RtlFreeUnicodeString( &valueW );
return status;
}
void init_unix_codepage(void)
{
USHORT *data = unix_funcs->get_unix_codepage_data();
@ -925,36 +775,6 @@ NTSTATUS WINAPI RtlSetThreadPreferredUILanguages( DWORD flags, PCZZWSTR buffer,
}
/**************************************************************************
* NtGetNlsSectionPtr (NTDLL.@)
*/
NTSTATUS WINAPI NtGetNlsSectionPtr( ULONG type, ULONG id, void *unknown, void **ptr, SIZE_T *size )
{
FILE_END_OF_FILE_INFORMATION info;
IO_STATUS_BLOCK io;
HANDLE file;
NTSTATUS status;
if ((status = open_nls_data_file( type, id, &file ))) return status;
if ((status = NtQueryInformationFile( file, &io, &info, sizeof(info), FileEndOfFileInformation )))
goto done;
/* FIXME: return a heap block instead of a file mapping for now */
if (!(*ptr = RtlAllocateHeap( GetProcessHeap(), 0, info.EndOfFile.QuadPart )))
{
status = STATUS_NO_MEMORY;
goto done;
}
status = NtReadFile( file, 0, NULL, NULL, &io, *ptr, info.EndOfFile.QuadPart, NULL, NULL );
if (!status && io.Information != info.EndOfFile.QuadPart) status = STATUS_INVALID_FILE_FOR_SECTION;
if (!status) *size = io.Information;
else RtlFreeHeap( GetProcessHeap(), 0, *ptr );
done:
NtClose( file );
return status;
}
/******************************************************************
* RtlInitCodePageTable (NTDLL.@)
*/

View file

@ -222,7 +222,7 @@
@ stdcall -norelay -syscall NtGetContextThread(long ptr)
@ stdcall -syscall NtGetCurrentProcessorNumber()
# @ stub NtGetDevicePowerState
@ stdcall NtGetNlsSectionPtr(long long long ptr ptr)
@ stdcall -syscall NtGetNlsSectionPtr(long long long ptr ptr)
@ stub NtGetPlugPlayEvent
@ stdcall NtGetTickCount()
@ stdcall -syscall NtGetWriteWatch(long long ptr long ptr ptr ptr)
@ -1226,7 +1226,7 @@
@ stdcall -private -norelay -syscall ZwGetContextThread(long ptr) NtGetContextThread
@ stdcall -private -syscall ZwGetCurrentProcessorNumber() NtGetCurrentProcessorNumber
# @ stub ZwGetDevicePowerState
@ stdcall -private ZwGetNlsSectionPtr(long long long ptr ptr) NtGetNlsSectionPtr
@ stdcall -private -syscall ZwGetNlsSectionPtr(long long long ptr ptr) NtGetNlsSectionPtr
@ stub ZwGetPlugPlayEvent
@ stdcall -private ZwGetTickCount() NtGetTickCount
@ stdcall -private -syscall ZwGetWriteWatch(long long ptr long ptr ptr ptr) NtGetWriteWatch

View file

@ -84,16 +84,49 @@ static struct
void *wctable;
} unix_cp;
static void *read_nls_file( const char *name )
enum nls_section_type
{
NLS_SECTION_SORTKEYS = 9,
NLS_SECTION_CASEMAP = 10,
NLS_SECTION_CODEPAGE = 11,
NLS_SECTION_NORMALIZE = 12
};
static char *get_nls_file_path( ULONG type, ULONG id )
{
const char *dir = build_dir ? build_dir : data_dir;
const char *name = NULL;
char *path, tmp[16];
switch (type)
{
case NLS_SECTION_SORTKEYS: name = "sortdefault"; break;
case NLS_SECTION_CASEMAP: name = "l_intl"; break;
case NLS_SECTION_CODEPAGE: name = tmp; sprintf( tmp, "c_%03u", id ); break;
case NLS_SECTION_NORMALIZE:
switch (id)
{
case NormalizationC: name = "normnfc"; break;
case NormalizationD: name = "normnfd"; break;
case NormalizationKC: name = "normnfkc"; break;
case NormalizationKD: name = "normnfkd"; break;
case 13: name = "normidna"; break;
}
break;
}
if (!name) return NULL;
if (!(path = malloc( strlen(dir) + strlen(name) + 10 ))) return NULL;
sprintf( path, "%s/nls/%s.nls", dir, name );
return path;
}
static void *read_nls_file( ULONG type, ULONG id )
{
char *path = get_nls_file_path( type, id );
struct stat st;
char *path;
void *data, *ret = NULL;
int fd;
if (!(path = malloc( strlen(dir) + 22 ))) return NULL;
sprintf( path, "%s/nls/%s.nls", dir, name );
if ((fd = open( path, O_RDONLY )) != -1)
{
fstat( fd, &st );
@ -109,11 +142,73 @@ static void *read_nls_file( const char *name )
}
close( fd );
}
else ERR( "failed to load %s\n", path );
else ERR( "failed to load %u/%u\n", type, id );
free( path );
return ret;
}
static NTSTATUS open_nls_data_file( ULONG type, ULONG id, HANDLE *file )
{
static const WCHAR systemdirW[] = {'\\','?','?','\\','C',':','\\','w','i','n','d','o','w','s','\\',
's','y','s','t','e','m','3','2','\\',0};
static const WCHAR sortdirW[] = {'\\','?','?','\\','C',':','\\','w','i','n','d','o','w','s','\\',
'g','l','o','b','a','l','i','z','a','t','i','o','n','\\',
's','o','r','t','i','n','g','\\',0};
NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND;
IO_STATUS_BLOCK io;
OBJECT_ATTRIBUTES attr = { sizeof(attr) };
UNICODE_STRING valueW;
WCHAR buffer[ARRAY_SIZE(sortdirW) + 16];
char *p, *path = get_nls_file_path( type, id );
if (!path) return STATUS_OBJECT_NAME_NOT_FOUND;
status = open_unix_file( file, path, GENERIC_READ, &attr, 0, FILE_SHARE_READ,
FILE_OPEN, FILE_SYNCHRONOUS_IO_ALERT, NULL, 0 );
if (status == STATUS_NO_SUCH_FILE)
{
/* try to open file in system dir */
ntdll_wcscpy( buffer, type == NLS_SECTION_SORTKEYS ? sortdirW : systemdirW );
p = strrchr( path, '/' ) + 1;
ascii_to_unicode( buffer + ntdll_wcslen(buffer), p, strlen(p) + 1 );
valueW.Buffer = buffer;
valueW.Length = ntdll_wcslen( buffer ) * sizeof(WCHAR);
valueW.MaximumLength = sizeof( buffer );
InitializeObjectAttributes( &attr, &valueW, 0, 0, NULL );
status = NtOpenFile( file, GENERIC_READ, &attr, &io, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_ALERT );
}
free( path );
return status;
}
static NTSTATUS get_nls_section_name( ULONG type, ULONG id, WCHAR name[32] )
{
char buffer[32];
switch (type)
{
case NLS_SECTION_SORTKEYS:
if (id) return STATUS_INVALID_PARAMETER_1;
strcpy( buffer, "\\NLS\\NlsSectionSORTDEFAULT" );
break;
case NLS_SECTION_CASEMAP:
if (id) return STATUS_UNSUCCESSFUL;
strcpy( buffer, "\\NLS\\NlsSectionLANG_INTL" );
break;
case NLS_SECTION_CODEPAGE:
sprintf( buffer, "\\NLS\\NlsSectionCP%03u", id);
break;
case NLS_SECTION_NORMALIZE:
sprintf( buffer, "\\NLS\\NlsSectionNORM%08x", id);
break;
default:
return STATUS_INVALID_PARAMETER_1;
}
ascii_to_unicode( name, buffer, strlen(buffer) + 1 );
return STATUS_SUCCESS;
}
static int get_utf16( const WCHAR *src, unsigned int srclen, unsigned int *ch )
{
@ -167,7 +262,7 @@ static struct norm_table *nfc_table;
static void init_unix_codepage(void)
{
nfc_table = read_nls_file( "normnfc" );
nfc_table = read_nls_file( NLS_SECTION_NORMALIZE, NormalizationC );
}
static void put_utf16( WCHAR *dst, unsigned int ch )
@ -398,11 +493,8 @@ static void init_unix_codepage(void)
{
if (charset_names[pos].cp != CP_UTF8)
{
char name[16];
void *data;
sprintf( name, "c_%03u", charset_names[pos].cp );
if ((data = read_nls_file( name ))) init_unix_cptable( data );
void *data = read_nls_file( NLS_SECTION_CODEPAGE, charset_names[pos].cp );
if (data) init_unix_cptable( data );
}
return;
}
@ -958,7 +1050,7 @@ void init_environment( int argc, char *argv[], char *envp[] )
init_unix_codepage();
init_locale();
if ((case_table = read_nls_file( "l_intl" )))
if ((case_table = read_nls_file( NLS_SECTION_CASEMAP, 0 )))
{
uctable = case_table + 2;
lctable = case_table + case_table[1] + 2;
@ -1283,6 +1375,43 @@ void CDECL get_locales( WCHAR *sys, WCHAR *user )
}
/**************************************************************************
* NtGetNlsSectionPtr (NTDLL.@)
*/
NTSTATUS WINAPI NtGetNlsSectionPtr( ULONG type, ULONG id, void *unknown, void **ptr, SIZE_T *size )
{
UNICODE_STRING nameW;
OBJECT_ATTRIBUTES attr;
WCHAR name[32];
HANDLE handle, file;
NTSTATUS status;
if ((status = get_nls_section_name( type, id, name ))) return status;
nameW.Buffer = name;
nameW.Length = ntdll_wcslen(name) * sizeof(WCHAR);
nameW.MaximumLength = sizeof(name);
InitializeObjectAttributes( &attr, &nameW, 0, 0, NULL );
if ((status = NtOpenSection( &handle, SECTION_MAP_READ, &attr )))
{
if ((status = open_nls_data_file( type, id, &file ))) return status;
attr.Attributes = OBJ_OPENIF | OBJ_PERMANENT;
status = NtCreateSection( &handle, SECTION_MAP_READ, &attr, NULL, PAGE_READONLY, SEC_COMMIT, file );
NtClose( file );
if (status == STATUS_OBJECT_NAME_EXISTS) status = STATUS_SUCCESS;
}
if (!status)
{
*ptr = NULL;
*size = 0;
status = NtMapViewOfSection( handle, GetCurrentProcess(), ptr, 0, 0, NULL, size,
ViewShare, 0, PAGE_READONLY );
}
NtClose( handle );
return status;
}
/**********************************************************************
* NtQueryDefaultLocale (NTDLL.@)
*/