Which optionally returns the original case of the last path component.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@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 *