[PATCH resend 1/2] ntdll: Allow renaming a file/directory to a different capitalization of itself.
Gabriel Ivăncescu
gabrielopcode at gmail.com
Thu Oct 8 09:55:48 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/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))
+ {
+ 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_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);
+ 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;
--
2.21.0
More information about the wine-devel
mailing list