[PATCH resend 1/2] ntdll: Allow renaming a file/directory to a different capitalization of itself.

Zebediah Figura zfigura at codeweavers.com
Sat Oct 24 16:36:41 CDT 2020


On 10/8/20 9:55 AM, Gabriel Ivăncescu wrote:
> Renaming a file or directory from e.g. foobar to FooBar (or any other
> caps-only change) should work and capitalize it, like on Windows, instead
> of being a no-op.
> 
> Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=46203
> Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
> ---
>  dlls/ntdll/unix/file.c | 48 ++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 46 insertions(+), 2 deletions(-)
> 
> diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
> index afb552b..639ea6c 100644
> --- a/dlls/ntdll/unix/file.c
> +++ b/dlls/ntdll/unix/file.c
> @@ -4326,9 +4326,10 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io,
>          if (len >= sizeof(FILE_RENAME_INFORMATION))
>          {
>              FILE_RENAME_INFORMATION *info = ptr;
> +            char *unix_name, *src_unix;
>              UNICODE_STRING name_str;
>              OBJECT_ATTRIBUTES attr;
> -            char *unix_name;
> +            size_t unix_name_len;
>  
>              name_str.Buffer = info->FileName;
>              name_str.Length = info->FileNameLength;
> @@ -4343,13 +4344,56 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io,
>              if (io->u.Status != STATUS_SUCCESS && io->u.Status != STATUS_NO_SUCH_FILE)
>                  break;
>  
> +            unix_name_len = strlen(unix_name);
> +
> +            /* When it's renaming to the same file, preserve the case sensitivity of the last
> +               component, so that renaming a\b\c\foobar to a\b\c\Foobar works correctly. */
> +            if (io->u.Status != STATUS_NO_SUCH_FILE && !server_get_unix_name(handle, &src_unix))
> +            {
> +                char *name = realpath(unix_name, NULL);
> +
> +                if (name && !strcmp(name, src_unix))
> +                {

Do we even need to make either of these checks?

(What happens if you try to clobber an existing file with different casing?)

> +                    size_t nt_filename_len, pathlen;
> +                    const WCHAR *nt_filename;
> +                    char *tmp;
> +                    INT maxsz;
> +
> +                    for (pathlen = name_str.Length / sizeof(WCHAR); pathlen; pathlen--)
> +                        if (name_str.Buffer[pathlen - 1] == '\\')
> +                            break;

wcsrchr()?

> +
> +                    nt_filename     = name_str.Buffer + pathlen;
> +                    nt_filename_len = name_str.Length / sizeof(WCHAR) - pathlen;
> +
> +                    /* Build it from path + filename (the latter converted from nt_filename) */
> +                    for (pathlen = unix_name_len; pathlen; pathlen--)
> +                        if (unix_name[pathlen - 1] == '/')
> +                            break;
> +
> +                    tmp = unix_name;
> +                    maxsz = pathlen + nt_filename_len * 3 + 1;
> +                    if (unix_name_len + 1 < maxsz) tmp = realloc(tmp, maxsz);

This reallocation strategy is very weird.

> +                    if (tmp)
> +                    {
> +                        unix_name = tmp;
> +                        unix_name_len = pathlen;
> +                        unix_name_len += ntdll_wcstoumbs(nt_filename, nt_filename_len,
> +                                                         unix_name + pathlen, maxsz - pathlen, TRUE);
> +                        unix_name[unix_name_len] = '\0';
> +                    }
> +                }
> +                free(src_unix);
> +                free(name);
> +            }
> +
>              SERVER_START_REQ( set_fd_name_info )
>              {
>                  req->handle   = wine_server_obj_handle( handle );
>                  req->rootdir  = wine_server_obj_handle( attr.RootDirectory );
>                  req->link     = FALSE;
>                  req->replace  = info->ReplaceIfExists;
> -                wine_server_add_data( req, unix_name, strlen(unix_name) );
> +                wine_server_add_data( req, unix_name, unix_name_len );
>                  io->u.Status = wine_server_call( req );
>              }
>              SERVER_END_REQ;
> 


-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: OpenPGP digital signature
URL: <http://www.winehq.org/pipermail/wine-devel/attachments/20201024/26d3950c/attachment.sig>


More information about the wine-devel mailing list