From 8fa03e494acb10303fef360b510c3da61f4edc34 Mon Sep 17 00:00:00 2001
From: Alexandre Julliard <julliard@winehq.org>
Date: Fri, 27 Nov 2020 16:41:07 +0100
Subject: [PATCH] server: Create the NLS section object for the l_intl.nls
 file.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
---
 server/directory.c | 16 ++++++++++------
 server/file.h      |  2 ++
 server/main.c      |  3 +--
 server/mapping.c   | 35 +++++++++++++++++++++++++++++++++++
 server/object.h    |  2 +-
 server/unicode.c   | 20 ++++++++++++++------
 server/unicode.h   |  2 +-
 7 files changed, 64 insertions(+), 16 deletions(-)

diff --git a/server/directory.c b/server/directory.c
index cd9afb3c457..81d02d6f64e 100644
--- a/server/directory.c
+++ b/server/directory.c
@@ -249,14 +249,12 @@ static void create_session( unsigned int id )
     static const WCHAR dir_bnolinksW[] = {'B','N','O','L','I','N','K','S'};
     static const WCHAR dir_bnoW[] = {'B','a','s','e','N','a','m','e','d','O','b','j','e','c','t','s'};
     static const WCHAR dir_dosdevicesW[] = {'D','o','s','D','e','v','i','c','e','s'};
-    static const WCHAR dir_nlsW[] = {'N','L','S'};
     static const WCHAR dir_windowsW[] = {'W','i','n','d','o','w','s'};
     static const WCHAR dir_winstationsW[] = {'W','i','n','d','o','w','S','t','a','t','i','o','n','s'};
     static const struct unicode_str dir_sessions_str = {dir_sessionsW, sizeof(dir_sessionsW)};
     static const struct unicode_str dir_bnolinks_str = {dir_bnolinksW, sizeof(dir_bnolinksW)};
     static const struct unicode_str dir_bno_str = {dir_bnoW, sizeof(dir_bnoW)};
     static const struct unicode_str dir_dosdevices_str = {dir_dosdevicesW, sizeof(dir_dosdevicesW)};
-    static const struct unicode_str dir_nls_str = {dir_nlsW, sizeof(dir_nlsW)};
     static const struct unicode_str dir_windows_str = {dir_windowsW, sizeof(dir_windowsW)};
     static const struct unicode_str dir_winstations_str = {dir_winstationsW, sizeof(dir_winstationsW)};
 
@@ -280,7 +278,6 @@ static void create_session( unsigned int id )
         dir_bno_global = create_directory( &root_directory->obj, &dir_bno_str, OBJ_PERMANENT, HASH_SIZE, NULL );
         dir_sessions   = create_directory( &root_directory->obj, &dir_sessions_str, OBJ_PERMANENT, HASH_SIZE, NULL );
         dir_bnolinks   = create_directory( &dir_sessions->obj, &dir_bnolinks_str, OBJ_PERMANENT, HASH_SIZE, NULL );
-        release_object( create_directory( &root_directory->obj, &dir_nls_str, OBJ_PERMANENT, HASH_SIZE, NULL ));
         release_object( dir_bno_global );
         release_object( dir_bnolinks );
         release_object( dir_sessions );
@@ -326,7 +323,7 @@ static void create_session( unsigned int id )
     free( id_strW );
 }
 
-void init_directories(void)
+void init_directories( struct fd *intl_fd )
 {
     /* Directories */
     static const WCHAR dir_globalW[] = {'?','?'};
@@ -334,11 +331,13 @@ void init_directories(void)
     static const WCHAR dir_deviceW[] = {'D','e','v','i','c','e'};
     static const WCHAR dir_objtypeW[] = {'O','b','j','e','c','t','T','y','p','e','s'};
     static const WCHAR dir_kernelW[] = {'K','e','r','n','e','l','O','b','j','e','c','t','s'};
+    static const WCHAR dir_nlsW[] = {'N','L','S'};
     static const struct unicode_str dir_global_str = {dir_globalW, sizeof(dir_globalW)};
     static const struct unicode_str dir_driver_str = {dir_driverW, sizeof(dir_driverW)};
     static const struct unicode_str dir_device_str = {dir_deviceW, sizeof(dir_deviceW)};
     static const struct unicode_str dir_objtype_str = {dir_objtypeW, sizeof(dir_objtypeW)};
     static const struct unicode_str dir_kernel_str = {dir_kernelW, sizeof(dir_kernelW)};
+    static const struct unicode_str dir_nls_str = {dir_nlsW, sizeof(dir_nlsW)};
 
     /* symlinks */
     static const WCHAR link_dosdevW[] = {'D','o','s','D','e','v','i','c','e','s'};
@@ -399,10 +398,12 @@ void init_directories(void)
     static const struct unicode_str keyed_event_crit_sect_str = {keyed_event_crit_sectW, sizeof(keyed_event_crit_sectW)};
 
     /* mappings */
+    static const WCHAR intlW[] = {'N','l','s','S','e','c','t','i','o','n','L','A','N','G','_','I','N','T','L'};
     static const WCHAR user_dataW[] = {'_','_','w','i','n','e','_','u','s','e','r','_','s','h','a','r','e','d','_','d','a','t','a'};
+    static const struct unicode_str intl_str = {intlW, sizeof(intlW)};
     static const struct unicode_str user_data_str = {user_dataW, sizeof(user_dataW)};
 
-    struct directory *dir_driver, *dir_device, *dir_global, *dir_kernel;
+    struct directory *dir_driver, *dir_device, *dir_global, *dir_kernel, *dir_nls;
     struct object *named_pipe_device, *mailslot_device, *null_device;
     unsigned int i;
 
@@ -412,6 +413,7 @@ void init_directories(void)
     dir_objtype    = create_directory( &root_directory->obj, &dir_objtype_str, OBJ_PERMANENT, HASH_SIZE, NULL );
     dir_kernel     = create_directory( &root_directory->obj, &dir_kernel_str, OBJ_PERMANENT, HASH_SIZE, NULL );
     dir_global     = create_directory( &root_directory->obj, &dir_global_str, OBJ_PERMANENT, HASH_SIZE, NULL );
+    dir_nls        = create_directory( &root_directory->obj, &dir_nls_str, OBJ_PERMANENT, HASH_SIZE, NULL );
 
     /* devices */
     named_pipe_device = create_named_pipe_device( &dir_device->obj, &named_pipe_str, OBJ_PERMANENT, NULL );
@@ -439,7 +441,8 @@ void init_directories(void)
         release_object( create_event( &dir_kernel->obj, &kernel_events[i], OBJ_PERMANENT, 1, 0, NULL ));
     release_object( create_keyed_event( &dir_kernel->obj, &keyed_event_crit_sect_str, OBJ_PERMANENT, NULL ));
 
-    /* user data mapping */
+    /* mappings */
+    release_object( create_fd_mapping( &dir_nls->obj, &intl_str, intl_fd, OBJ_PERMANENT, NULL ));
     release_object( create_user_data_mapping( &dir_kernel->obj, &user_data_str, OBJ_PERMANENT, NULL ));
 
     release_object( named_pipe_device );
@@ -450,6 +453,7 @@ void init_directories(void)
     release_object( dir_device );
     release_object( dir_objtype );
     release_object( dir_kernel );
+    release_object( dir_nls );
     release_object( dir_global );
 }
 
diff --git a/server/file.h b/server/file.h
index 2fb634fad8d..69f2bed6cd6 100644
--- a/server/file.h
+++ b/server/file.h
@@ -171,6 +171,8 @@ extern struct file *get_mapping_file( struct process *process, client_ptr_t base
 extern const pe_image_info_t *get_mapping_image_info( struct process *process, client_ptr_t base );
 extern void free_mapped_views( struct process *process );
 extern int get_page_size(void);
+extern struct mapping *create_fd_mapping( struct object *root, const struct unicode_str *name, struct fd *fd,
+                                          unsigned int attr, const struct security_descriptor *sd );
 extern struct object *create_user_data_mapping( struct object *root, const struct unicode_str *name,
                                                 unsigned int attr, const struct security_descriptor *sd );
 
diff --git a/server/main.c b/server/main.c
index 5d7881a6af9..d7aed0da199 100644
--- a/server/main.c
+++ b/server/main.c
@@ -144,8 +144,7 @@ int main( int argc, char *argv[] )
     if (debug_level) fprintf( stderr, "wineserver: starting (pid=%ld)\n", (long) getpid() );
     set_current_time();
     init_signals();
-    load_intl_file();
-    init_directories();
+    init_directories( load_intl_file() );
     init_registry();
     main_loop();
     return 0;
diff --git a/server/mapping.c b/server/mapping.c
index 769a986ae21..6c2e7a1fd2b 100644
--- a/server/mapping.c
+++ b/server/mapping.c
@@ -883,6 +883,41 @@ static struct mapping *create_mapping( struct object *root, const struct unicode
     return NULL;
 }
 
+/* create a read-only file mapping for the specified fd */
+struct mapping *create_fd_mapping( struct object *root, const struct unicode_str *name,
+                                   struct fd *fd, unsigned int attr, const struct security_descriptor *sd )
+{
+    struct mapping *mapping;
+    int unix_fd;
+    struct stat st;
+
+    if (!(mapping = create_named_object( root, &mapping_ops, name, attr, sd ))) return NULL;
+    if (get_error() == STATUS_OBJECT_NAME_EXISTS) return mapping;  /* Nothing else to do */
+
+    mapping->shared    = NULL;
+    mapping->committed = NULL;
+    mapping->flags     = SEC_FILE;
+    mapping->fd        = (struct fd *)grab_object( fd );
+    set_fd_user( mapping->fd, &mapping_fd_ops, NULL );
+
+    if ((unix_fd = get_unix_fd( mapping->fd )) == -1) goto error;
+    if (fstat( unix_fd, &st ) == -1)
+    {
+        file_set_error();
+        goto error;
+    }
+    if (!(mapping->size = st.st_size))
+    {
+        set_error( STATUS_MAPPED_FILE_SIZE_ZERO );
+        goto error;
+    }
+    return mapping;
+
+ error:
+    release_object( mapping );
+    return NULL;
+}
+
 static struct mapping *get_mapping_obj( struct process *process, obj_handle_t handle, unsigned int access )
 {
     return (struct mapping *)get_handle_obj( process, handle, access, &mapping_ops );
diff --git a/server/object.h b/server/object.h
index 3b3e9084798..73058fd3f99 100644
--- a/server/object.h
+++ b/server/object.h
@@ -244,7 +244,7 @@ extern struct object *get_root_directory(void);
 extern struct object *get_directory_obj( struct process *process, obj_handle_t handle );
 extern struct object_type *get_object_type( const struct unicode_str *name );
 extern int directory_link_name( struct object *obj, struct object_name *name, struct object *parent );
-extern void init_directories(void);
+extern void init_directories( struct fd *intl_fd );
 
 /* symbolic link functions */
 
diff --git a/server/unicode.c b/server/unicode.c
index 0dde757313b..56f3c024103 100644
--- a/server/unicode.c
+++ b/server/unicode.c
@@ -23,9 +23,13 @@
 
 #include <ctype.h>
 #include <stdio.h>
+#include <stdarg.h>
 
+#include "windef.h"
+#include "winternl.h"
 #include "request.h"
 #include "unicode.h"
+#include "file.h"
 
 /* number of following bytes in sequence based on first byte value (for bytes above 0x7f) */
 static const char utf8_length[128] =
@@ -257,13 +261,15 @@ static char *get_nls_dir(void)
 }
 
 /* load the case mapping table */
-void load_intl_file(void)
+struct fd *load_intl_file(void)
 {
     static const char *nls_dirs[] = { NULL, NLSDIR, "/usr/local/share/wine/nls", "/usr/share/wine/nls" };
     unsigned int i, offset, size;
     unsigned short data;
     char *path;
-    int unix_fd = -1;
+    struct fd *fd = NULL;
+    int unix_fd;
+    mode_t mode = 0600;
 
     nls_dirs[0] = get_nls_dir();
     for (i = 0; i < ARRAY_SIZE( nls_dirs ); i++)
@@ -272,10 +278,13 @@ void load_intl_file(void)
         if (!(path = malloc( strlen(nls_dirs[i]) + sizeof("/l_intl.nls" )))) continue;
         strcpy( path, nls_dirs[i] );
         strcat( path, "/l_intl.nls" );
-        if ((unix_fd = open( path, O_RDONLY )) != -1) break;
+        if ((fd = open_fd( NULL, path, O_RDONLY, &mode, FILE_READ_DATA,
+                           FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                           FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ))) break;
         free( path );
     }
-    if (unix_fd == -1) fatal_error( "failed to load l_intl.nls\n" );
+    if (!fd) fatal_error( "failed to load l_intl.nls\n" );
+    unix_fd = get_unix_fd( fd );
     /* read initial offset */
     if (pread( unix_fd, &data, sizeof(data), 0 ) != sizeof(data) || !data) goto failed;
     offset = data;
@@ -289,9 +298,8 @@ void load_intl_file(void)
     /* read lowercase table */
     if (!(casemap = malloc( size * 2 ))) goto failed;
     if (pread( unix_fd, casemap, size * 2, offset * 2 ) != size * 2) goto failed;
-    close( unix_fd );
     free( path );
-    return;
+    return fd;
 
 failed:
     fatal_error( "invalid format for casemap table %s\n", path );
diff --git a/server/unicode.h b/server/unicode.h
index ddbbe4b5cfc..e031d6ef0cf 100644
--- a/server/unicode.h
+++ b/server/unicode.h
@@ -31,6 +31,6 @@ extern unsigned int hash_strW( const WCHAR *str, data_size_t len, unsigned int h
 extern WCHAR *ascii_to_unicode_str( const char *str, struct unicode_str *ret );
 extern int parse_strW( WCHAR *buffer, data_size_t *len, const char *src, char endchar );
 extern int dump_strW( const WCHAR *str, data_size_t len, FILE *f, const char escape[2] );
-extern void load_intl_file(void);
+extern struct fd *load_intl_file(void);
 
 #endif  /* __WINE_SERVER_UNICODE_H */
-- 
GitLab