[PATCH v11 1/2] ntdll: Introduce new nt_to_unix_file_name_with_case helper.

Gabriel Ivăncescu gabrielopcode at gmail.com
Thu May 20 10:35:25 CDT 2021


Which optionally returns the original case of the last path component.

Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
---
 dlls/ntdll/unix/file.c | 66 +++++++++++++++++++++++++++---------------
 1 file changed, 43 insertions(+), 23 deletions(-)

diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index c033bb0..e649745 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -3113,13 +3113,13 @@ done:
  * Helper for nt_to_unix_file_name
  */
 static NTSTATUS lookup_unix_name( const WCHAR *name, int name_len, char **buffer, int unix_len, int pos,
-                                  UINT disposition, BOOL is_unix )
+                                  char **case_ret, UINT disposition, BOOL is_unix )
 {
     static const WCHAR invalid_charsW[] = { INVALID_NT_CHARS, '/', 0 };
     NTSTATUS status;
     int ret;
     struct stat st;
-    char *unix_name = *buffer;
+    char *unix_name = *buffer, file_case[MAX_DIR_ENTRY_LEN + 1];
     const WCHAR *ptr, *end;
 
     /* check syntax of individual components */
@@ -3157,6 +3157,12 @@ static NTSTATUS lookup_unix_name( const WCHAR *name, int name_len, char **buffer
         for (p = unix_name + pos ; *p; p++) if (*p == '\\') *p = '/';
         if (!stat( unix_name, &st ))
         {
+            if (case_ret)
+            {
+                char *p = unix_name + pos + 1, *tmp = p;
+                while (*p) if (*p++ == '/' && *p) tmp = p;
+                *case_ret = strdup( tmp );
+            }
             if (disposition == FILE_CREATE) return STATUS_OBJECT_NAME_COLLISION;
             return STATUS_SUCCESS;
         }
@@ -3169,6 +3175,7 @@ static NTSTATUS lookup_unix_name( const WCHAR *name, int name_len, char **buffer
 
     /* now do it component by component */
 
+    file_case[0] = 0;
     while (name_len)
     {
         const WCHAR *end, *next;
@@ -3194,19 +3201,20 @@ static NTSTATUS lookup_unix_name( const WCHAR *name, int name_len, char **buffer
         /* if this is the last element, not finding it is not necessarily fatal */
         if (!name_len)
         {
+            ret = ntdll_wcstoumbs( name, end - name, file_case, MAX_DIR_ENTRY_LEN + 1, TRUE );
+            if (ret < 0 || ret > MAX_DIR_ENTRY_LEN) ret = 0;
+            file_case[ret] = 0;
+
             if (status == STATUS_OBJECT_PATH_NOT_FOUND)
             {
                 status = STATUS_OBJECT_NAME_NOT_FOUND;
-                if (disposition != FILE_OPEN && disposition != FILE_OVERWRITE)
+                if (disposition != FILE_OPEN && disposition != FILE_OVERWRITE && ret)
                 {
-                    ret = ntdll_wcstoumbs( name, end - name, unix_name + pos + 1, MAX_DIR_ENTRY_LEN + 1, TRUE );
-                    if (ret > 0 && ret <= MAX_DIR_ENTRY_LEN)
-                    {
-                        unix_name[pos] = '/';
-                        unix_name[pos + 1 + ret] = 0;
-                        status = STATUS_NO_SUCH_FILE;
-                        break;
-                    }
+                    strcpy( unix_name + pos + 1, file_case );
+                    unix_name[pos] = '/';
+                    unix_name[pos + 1 + ret] = 0;
+                    status = STATUS_NO_SUCH_FILE;
+                    break;
                 }
             }
             else if (status == STATUS_SUCCESS && disposition == FILE_CREATE)
@@ -3221,6 +3229,7 @@ static NTSTATUS lookup_unix_name( const WCHAR *name, int name_len, char **buffer
         name = next;
     }
 
+    if (case_ret) *case_ret = strdup( file_case );
     return status;
 }
 
@@ -3229,7 +3238,7 @@ static NTSTATUS lookup_unix_name( const WCHAR *name, int name_len, char **buffer
  *           nt_to_unix_file_name_no_root
  */
 static NTSTATUS nt_to_unix_file_name_no_root( const UNICODE_STRING *nameW, char **unix_name_ret,
-                                              UINT disposition )
+                                              char **case_ret, UINT disposition )
 {
     static const WCHAR unixW[] = {'u','n','i','x'};
     static const WCHAR invalid_charsW[] = { INVALID_NT_CHARS, 0 };
@@ -3245,6 +3254,7 @@ static NTSTATUS nt_to_unix_file_name_no_root( const UNICODE_STRING *nameW, char
     name     = nameW->Buffer;
     name_len = nameW->Length / sizeof(WCHAR);
 
+    if (case_ret) *case_ret = NULL;
     if (!name_len || name[0] != '\\') return STATUS_OBJECT_PATH_SYNTAX_BAD;
 
     if (!(pos = get_dos_prefix_len( nameW )))
@@ -3323,7 +3333,7 @@ static NTSTATUS nt_to_unix_file_name_no_root( const UNICODE_STRING *nameW, char
     name += prefix_len;
     name_len -= prefix_len;
 
-    status = lookup_unix_name( name, name_len, &unix_name, unix_len, pos, disposition, is_unix );
+    status = lookup_unix_name( name, name_len, &unix_name, unix_len, pos, case_ret, disposition, is_unix );
     if (status == STATUS_SUCCESS || status == STATUS_NO_SUCH_FILE)
     {
         TRACE( "%s -> %s\n", debugstr_us(nameW), debugstr_a(unix_name) );
@@ -3339,15 +3349,9 @@ static NTSTATUS nt_to_unix_file_name_no_root( const UNICODE_STRING *nameW, char
 
 
 /******************************************************************************
- *           nt_to_unix_file_name
- *
- * Convert a file name from NT namespace to Unix namespace.
- *
- * If disposition is not FILE_OPEN or FILE_OVERWRITE, the last path
- * element doesn't have to exist; in that case STATUS_NO_SUCH_FILE is
- * returned, but the unix name is still filled in properly.
+ *           nt_to_unix_file_name_with_case
  */
-NTSTATUS nt_to_unix_file_name( const OBJECT_ATTRIBUTES *attr, char **name_ret, UINT disposition )
+static NTSTATUS nt_to_unix_file_name_with_case( const OBJECT_ATTRIBUTES *attr, char **name_ret, char **case_ret, UINT disposition )
 {
     enum server_fd_type type;
     int old_cwd, root_fd, needs_close;
@@ -3357,11 +3361,12 @@ NTSTATUS nt_to_unix_file_name( const OBJECT_ATTRIBUTES *attr, char **name_ret, U
     NTSTATUS status;
 
     if (!attr->RootDirectory)  /* without root dir fall back to normal lookup */
-        return nt_to_unix_file_name_no_root( attr->ObjectName, name_ret, disposition );
+        return nt_to_unix_file_name_no_root( attr->ObjectName, name_ret, case_ret, disposition );
 
     name     = attr->ObjectName->Buffer;
     name_len = attr->ObjectName->Length / sizeof(WCHAR);
 
+    if (case_ret) *case_ret = NULL;
     if (name_len && name[0] == '\\') return STATUS_INVALID_PARAMETER;
 
     unix_len = name_len * 3 + MAX_DIR_ENTRY_LEN + 3;
@@ -3380,7 +3385,7 @@ NTSTATUS nt_to_unix_file_name( const OBJECT_ATTRIBUTES *attr, char **name_ret, U
             mutex_lock( &dir_mutex );
             if ((old_cwd = open( ".", O_RDONLY )) != -1 && fchdir( root_fd ) != -1)
             {
-                status = lookup_unix_name( name, name_len, &unix_name, unix_len, 1, disposition, FALSE );
+                status = lookup_unix_name( name, name_len, &unix_name, unix_len, 1, case_ret, disposition, FALSE );
                 if (fchdir( old_cwd ) == -1) chdir( "/" );
             }
             else status = errno_to_status( errno );
@@ -3405,6 +3410,21 @@ NTSTATUS nt_to_unix_file_name( const OBJECT_ATTRIBUTES *attr, char **name_ret, U
 }
 
 
+/******************************************************************************
+ *           nt_to_unix_file_name
+ *
+ * Convert a file name from NT namespace to Unix namespace.
+ *
+ * If disposition is not FILE_OPEN or FILE_OVERWRITE, the last path
+ * element doesn't have to exist; in that case STATUS_NO_SUCH_FILE is
+ * returned, but the unix name is still filled in properly.
+ */
+NTSTATUS nt_to_unix_file_name( const OBJECT_ATTRIBUTES *attr, char **name_ret, UINT disposition )
+{
+    return nt_to_unix_file_name_with_case( attr, name_ret, NULL, disposition );
+}
+
+
 /******************************************************************************
  *           wine_nt_to_unix_file_name
  *
-- 
2.30.0




More information about the wine-devel mailing list