Matteo Bruni : ntdll: Implement a read_directory_getattrlist() function.

Alexandre Julliard julliard at wine.codeweavers.com
Wed May 20 10:04:11 CDT 2015


Module: wine
Branch: master
Commit: 5d65b9d0c2af38e11b59719f3888944ad29b41b1
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=5d65b9d0c2af38e11b59719f3888944ad29b41b1

Author: Matteo Bruni <mbruni at codeweavers.com>
Date:   Tue May 19 23:59:06 2015 +0200

ntdll: Implement a read_directory_getattrlist() function.

When searching for a specific filename on a case-insensitive filesystem
we first try with stat(). If stat() does find the file we currently
return the requested filename back.

That presents an issue when the application cares about the casing of the
actual file stored on-disk. Specifically, NtQueryDirectoryFile is
supposed to return the actual filename with correct casing.

One possible solution to the issue, without having to resort to manually
scanning the directory entries, is to make use of the OS X getattrlist()
function, since it can return the filename stored on the filesystem.

---

 dlls/ntdll/directory.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 79 insertions(+), 2 deletions(-)

diff --git a/dlls/ntdll/directory.c b/dlls/ntdll/directory.c
index cbfc022..81b5c2e 100644
--- a/dlls/ntdll/directory.c
+++ b/dlls/ntdll/directory.c
@@ -2112,6 +2112,77 @@ done:
     return ret;
 }
 
+#ifdef HAVE_GETATTRLIST
+/***********************************************************************
+ *           read_directory_getattrlist
+ *
+ * Read a single file from a directory by determining whether the file
+ * identified by mask exists using getattrlist.
+ */
+static int read_directory_getattrlist( int fd, IO_STATUS_BLOCK *io, void *buffer, ULONG length,
+                                       BOOLEAN single_entry, const UNICODE_STRING *mask,
+                                       BOOLEAN restart_scan, FILE_INFORMATION_CLASS class )
+{
+    int unix_len, ret, used_default;
+    char *unix_name;
+    struct attrlist attrlist;
+    struct
+    {
+        u_int32_t length;
+        struct attrreference name_reference;
+        char name[NAME_MAX + 1];
+    } attrlist_buffer;
+
+    TRACE("looking up file %s\n", debugstr_us( mask ));
+
+    unix_len = ntdll_wcstoumbs( 0, mask->Buffer, mask->Length / sizeof(WCHAR), NULL, 0, NULL, NULL );
+    if (!(unix_name = RtlAllocateHeap( GetProcessHeap(), 0, unix_len + 1)))
+    {
+        io->u.Status = STATUS_NO_MEMORY;
+        return 0;
+    }
+    ret = ntdll_wcstoumbs( 0, mask->Buffer, mask->Length / sizeof(WCHAR), unix_name, unix_len,
+                           NULL, &used_default );
+    if (ret > 0 && !used_default)
+    {
+        unix_name[ret] = 0;
+        if (restart_scan)
+        {
+            lseek( fd, 0, SEEK_SET );
+        }
+        else if (lseek( fd, 0, SEEK_CUR ) != 0)
+        {
+            io->u.Status = STATUS_NO_MORE_FILES;
+            ret = 0;
+            goto done;
+        }
+
+        memset( &attrlist, 0, sizeof(attrlist) );
+        attrlist.bitmapcount = ATTR_BIT_MAP_COUNT;
+        attrlist.commonattr = ATTR_CMN_NAME;
+        ret = getattrlist( unix_name, &attrlist, &attrlist_buffer, sizeof(attrlist_buffer), 0 );
+        if (!ret)
+        {
+            union file_directory_info *info = append_entry( buffer, io, length, attrlist_buffer.name, NULL, NULL, class );
+            if (info)
+            {
+                info->next = 0;
+                if (io->u.Status != STATUS_BUFFER_OVERFLOW) lseek( fd, 1, SEEK_CUR );
+            }
+            else io->u.Status = STATUS_NO_MORE_FILES;
+        }
+    }
+    else ret = -1;
+
+done:
+    RtlFreeHeap( GetProcessHeap(), 0, unix_name );
+
+    TRACE("returning %d\n", ret);
+
+    return ret;
+}
+#endif
+
 
 /******************************************************************************
  *  NtQueryDirectoryFile	[NTDLL.@]
@@ -2173,9 +2244,15 @@ NTSTATUS WINAPI NtQueryDirectoryFile( HANDLE handle, HANDLE event,
         if ((read_directory_vfat( fd, io, buffer, length, single_entry,
                                   mask, restart_scan, info_class )) != -1) goto done;
 #endif
-        if (!has_wildcard( mask ) &&
-            read_directory_stat( fd, io, buffer, length, single_entry,
+        if (!has_wildcard( mask ))
+        {
+#ifdef HAVE_GETATTRLIST
+            if (read_directory_getattrlist( fd, io, buffer, length, single_entry,
                                  mask, restart_scan, info_class ) != -1) goto done;
+#endif
+            if (read_directory_stat( fd, io, buffer, length, single_entry,
+                                 mask, restart_scan, info_class ) != -1) goto done;
+        }
 #ifdef USE_GETDENTS
         if ((read_directory_getdents( fd, io, buffer, length, single_entry,
                                       mask, restart_scan, info_class )) != -1) goto done;




More information about the wine-cvs mailing list