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

Gabriel Ivăncescu gabrielopcode at gmail.com
Fri Mar 20 12:21:46 CDT 2020


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/file.c | 44 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 43 insertions(+), 1 deletion(-)

diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index 5175e9d..378584d 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -2761,9 +2761,9 @@ NTSTATUS WINAPI NtSetInformationFile(HANDLE handle, PIO_STATUS_BLOCK io,
         if (len >= sizeof(FILE_RENAME_INFORMATION))
         {
             FILE_RENAME_INFORMATION *info = ptr;
+            ANSI_STRING unix_name, src_unix;
             UNICODE_STRING name_str;
             OBJECT_ATTRIBUTES attr;
-            ANSI_STRING unix_name;
 
             name_str.Buffer = info->FileName;
             name_str.Length = info->FileNameLength;
@@ -2778,6 +2778,48 @@ NTSTATUS WINAPI NtSetInformationFile(HANDLE handle, PIO_STATUS_BLOCK io,
             if (io->u.Status != STATUS_SUCCESS && io->u.Status != STATUS_NO_SUCH_FILE)
                 break;
 
+            /* 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)))
+            {
+                if (src_unix.Length == unix_name.Length &&
+                    !memcmp(src_unix.Buffer, unix_name.Buffer, unix_name.Length))
+                {
+                    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;
+
+                    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.Length; pathlen; pathlen--)
+                        if (unix_name.Buffer[pathlen - 1] == '/')
+                            break;
+
+                    tmp = unix_name.Buffer;
+                    maxsz = pathlen + nt_filename_len * 3 + 1;
+                    if (unix_name.MaximumLength < maxsz)
+                        tmp = RtlReAllocateHeap(GetProcessHeap(), 0, tmp, maxsz);
+                    if (tmp)
+                    {
+                        unix_name.Buffer = tmp;
+                        unix_name.MaximumLength = maxsz;
+
+                        unix_name.Length = pathlen;
+                        unix_name.Length += ntdll_wcstoumbs(nt_filename, nt_filename_len,
+                                                            unix_name.Buffer + pathlen, maxsz - pathlen, TRUE);
+                        unix_name.Buffer[unix_name.Length] = '\0';
+                    }
+                }
+                RtlFreeAnsiString(&src_unix);
+            }
+
             SERVER_START_REQ( set_fd_name_info )
             {
                 req->handle   = wine_server_obj_handle( handle );
-- 
2.21.0




More information about the wine-devel mailing list