[PATCH v11 1/2] ntdll: Introduce new nt_to_unix_file_name_with_case helper.
Rémi Bernon
rbernon at codeweavers.com
Thu May 20 10:56:08 CDT 2021
On 5/20/21 5:35 PM, Gabriel Ivăncescu wrote:
> 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;
> }
>
In addition to the comments I made on the previous version, I think this
is also possibly leaking things in case_ret, depending on the status
returned.
It may be better instead to take a bit of time considering a similar
approach as for name_ret, where nt_to_unix_file_name(_no_root) would
provide instead the case_ret / case_len buffer, returning it in the same
way name_ret is.
--
Rémi Bernon <rbernon at codeweavers.com>
More information about the wine-devel
mailing list