[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