From: Zebediah Figura zfigura@codeweavers.com
find_object_index() sets the status code to STATUS_NO_MORE_ENTRIES to indicate that the given index does not exist in the list of the directory entries, in addition to returning NULL.
STATUS_NO_MORE_ENTRIES only makes sense in the context of the function's only caller, req_get_directory_entry(), which is used to implement the NtQueryDirectoryObject() system call, specifically the single object case. Otherwise, the choice of status code is unintuitive.
Remove the set_error() call in find_object_index(), and move the responsibility of setting the status code to the caller. --- server/directory.c | 1 + server/object.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-)
diff --git a/server/directory.c b/server/directory.c index 23d7eb0a2b7..fdcfe9bef21 100644 --- a/server/directory.c +++ b/server/directory.c @@ -562,6 +562,7 @@ DECL_HANDLER(get_directory_entry)
release_object( obj ); } + else set_error( STATUS_NO_MORE_ENTRIES ); release_object( dir ); } } diff --git a/server/object.c b/server/object.c index 89e541ffb6b..459ead5f3a5 100644 --- a/server/object.c +++ b/server/object.c @@ -495,7 +495,6 @@ struct object *find_object_index( const struct namespace *namespace, unsigned in if (!index--) return grab_object( ptr->obj ); } } - set_error( STATUS_NO_MORE_ENTRIES ); return NULL; }
From: Jinoh Kang jinoh.kang.kr@gmail.com
--- dlls/wow64/sync.c | 66 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 54 insertions(+), 12 deletions(-)
diff --git a/dlls/wow64/sync.c b/dlls/wow64/sync.c index 681aab7e827..4b2a2d2093f 100644 --- a/dlls/wow64/sync.c +++ b/dlls/wow64/sync.c @@ -775,21 +775,63 @@ NTSTATUS WINAPI wow64_NtQueryDirectoryObject( UINT *args ) DIRECTORY_BASIC_INFORMATION *info; ULONG size = size32 + 2 * sizeof(*info) - 2 * sizeof(*info32);
- if (!single_entry) FIXME( "not implemented\n" ); info = Wow64AllocateTemp( size ); status = NtQueryDirectoryObject( handle, info, size, single_entry, restart, context, &retsize ); - if (!status) + if (NT_SUCCESS(status)) { - info32->ObjectName.Buffer = PtrToUlong( info32 + 2 ); - info32->ObjectName.Length = info->ObjectName.Length; - info32->ObjectName.MaximumLength = info->ObjectName.MaximumLength; - info32->ObjectTypeName.Buffer = info32->ObjectName.Buffer + info->ObjectName.MaximumLength; - info32->ObjectTypeName.Length = info->ObjectTypeName.Length; - info32->ObjectTypeName.MaximumLength = info->ObjectTypeName.MaximumLength; - memset( info32 + 1, 0, sizeof(*info32) ); - size = info->ObjectName.MaximumLength + info->ObjectTypeName.MaximumLength; - memcpy( info32 + 2, info + 2, size ); - if (retlen) *retlen = 2 * sizeof(*info32) + size; + unsigned int i, count, used_size, used_count, strpool_head, validsize = min( size, retsize ); + + used_count = 0; + used_size = sizeof(*info32); /* "null terminator" entry */ + for (count = 0; + sizeof(*info) * (count + 1) <= validsize && info[count].ObjectName.MaximumLength; + count++) + { + unsigned int entry_size = sizeof(*info32) + + info[count].ObjectName.MaximumLength + + info[count].ObjectTypeName.MaximumLength; + + if (used_size + entry_size <= size32) + { + used_count++; + used_size += entry_size; + } + } + + if (used_count != count) + { + ERR( "64bit dir list (%u+%lu bytes, %u entries) truncated for 32bit buffer (%u+%lu bytes, %u entries)\n", + validsize, size - validsize, count, used_size, size32 - min( size32, used_size ), used_count ); + + if (!status) status = STATUS_MORE_ENTRIES; + *context -= count - used_count; + } + + /* + * Avoid making strpool_head a pointer, since it can point beyond end + * of the buffer. Out-of-bounds pointers trigger undefined behavior + * just by existing, even when they are never dereferenced. + */ + strpool_head = sizeof(*info32) * (used_count + 1); /* after the "null terminator" entry */ + for (i = 0; i < used_count; i++) + { + info32[i].ObjectName.Buffer = PtrToUlong( (char *)info32 + strpool_head ); + info32[i].ObjectName.Length = info[i].ObjectName.Length; + info32[i].ObjectName.MaximumLength = info[i].ObjectName.MaximumLength; + memcpy( (char *)info32 + strpool_head, info[i].ObjectName.Buffer, info[i].ObjectName.MaximumLength ); + strpool_head += info[i].ObjectName.MaximumLength; + + info32[i].ObjectTypeName.Buffer = PtrToUlong( (char *)info32 + strpool_head ); + info32[i].ObjectTypeName.Length = info[i].ObjectTypeName.Length; + info32[i].ObjectTypeName.MaximumLength = info[i].ObjectTypeName.MaximumLength; + memcpy( (char *)info32 + strpool_head, info[i].ObjectTypeName.Buffer, info[i].ObjectTypeName.MaximumLength ); + strpool_head += info[i].ObjectTypeName.MaximumLength; + } + + if (size32 >= sizeof(*info32)) + memset( &info32[used_count], 0, sizeof(info32[used_count]) ); + + if (retlen) *retlen = strpool_head; } else if (retlen && status == STATUS_BUFFER_TOO_SMALL) *retlen = retsize - 2 * sizeof(*info) + 2 * sizeof(*info32);
From: Zebediah Figura zfigura@codeweavers.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52585 --- dlls/ntdll/tests/om.c | 57 ++++++++++++--------------- dlls/ntdll/unix/sync.c | 89 ++++++++++++++++++++++++++++++++++++++---- server/directory.c | 75 +++++++++++++++++++++++++++++++++++ server/protocol.def | 18 +++++++++ server/trace.c | 34 ++++++++++++++++ 5 files changed, 232 insertions(+), 41 deletions(-)
diff --git a/dlls/ntdll/tests/om.c b/dlls/ntdll/tests/om.c index 62659fc8cb4..5c6a82388d8 100644 --- a/dlls/ntdll/tests/om.c +++ b/dlls/ntdll/tests/om.c @@ -2627,9 +2627,9 @@ static void test_query_directory(void) context = 0xdeadbeef; size = 0xdeadbeef; status = NtQueryDirectoryObject( dir, info, 0, FALSE, TRUE, &context, &size ); - todo_wine ok( status == STATUS_NO_MORE_ENTRIES, "got %#lx\n", status ); + ok( status == STATUS_NO_MORE_ENTRIES, "got %#lx\n", status ); ok( context == 0xdeadbeef, "got context %#lx\n", context ); - todo_wine ok( size == sizeof(*info) || (is_wow64 && !size), "got size %lu\n", size ); + ok( size == sizeof(*info) || (is_wow64 && !size), "got size %lu\n", size );
context = 0xdeadbeef; size = 0xdeadbeef; @@ -2645,9 +2645,9 @@ static void test_query_directory(void) size = 0xdeadbeef; memset( buffer, 0xcc, sizeof(buffer) ); status = NtQueryDirectoryObject( dir, info, sizeof(buffer), FALSE, TRUE, &context, &size ); - todo_wine ok( status == STATUS_NO_MORE_ENTRIES, "got %#lx\n", status ); + ok( status == STATUS_NO_MORE_ENTRIES, "got %#lx\n", status ); ok( context == 0xdeadbeef, "got context %#lx\n", context ); - todo_wine ok( size == sizeof(*info) || (is_wow64 && !size), "got size %lu\n", size ); + ok( size == sizeof(*info) || (is_wow64 && !size), "got size %lu\n", size ); if (size == sizeof(*info)) ok( !memcmp( &info[0], &empty_info, sizeof(*info) ), "entry was not cleared\n" );
@@ -2743,37 +2743,31 @@ static void test_query_directory(void)
memset( buffer, 0xcc, sizeof(buffer) ); status = NtQueryDirectoryObject( dir, info, sizeof(buffer), FALSE, TRUE, &context, &size ); - todo_wine ok( !status, "got %#lx\n", status ); - if (!status) - { - ok( context == 2, "got context %#lx\n", context ); - check_unicode_string( &info[0].ObjectName, name1 ); - check_unicode_string( &info[0].ObjectTypeName, L"Mutant" ); - check_unicode_string( &info[1].ObjectName, name2 ); - check_unicode_string( &info[1].ObjectTypeName, L"Mutant" ); - ok( !memcmp( &info[2], &empty_info, sizeof(*info) ), "entry was not cleared\n" ); - } + ok( !status, "got %#lx\n", status ); + ok( context == 2, "got context %#lx\n", context ); + check_unicode_string( &info[0].ObjectName, name1 ); + check_unicode_string( &info[0].ObjectTypeName, L"Mutant" ); + check_unicode_string( &info[1].ObjectName, name2 ); + check_unicode_string( &info[1].ObjectTypeName, L"Mutant" ); + ok( !memcmp( &info[2], &empty_info, sizeof(*info) ), "entry was not cleared\n" );
needed_size = size; size = 0xdeadbeef; context = 0xdeadbeef; memset( buffer, 0xcc, sizeof(buffer) ); status = NtQueryDirectoryObject( dir, info, needed_size - 1, FALSE, TRUE, &context, &size ); - todo_wine ok( status == STATUS_MORE_ENTRIES, "got %#lx\n", status ); - if (status == STATUS_MORE_ENTRIES) - { - ok( context == 1, "got context %#lx\n", context ); - ok( size > 0 && size < needed_size, "got size %lu\n", size ); - check_unicode_string( &info[0].ObjectName, name1 ); - check_unicode_string( &info[0].ObjectTypeName, L"Mutant" ); - ok( !memcmp( &info[1], &empty_info, sizeof(*info) ), "entry was not cleared\n" ); - } + ok( status == STATUS_MORE_ENTRIES, "got %#lx\n", status ); + ok( context == 1, "got context %#lx\n", context ); + ok( size > 0 && size < needed_size, "got size %lu\n", size ); + check_unicode_string( &info[0].ObjectName, name1 ); + check_unicode_string( &info[0].ObjectTypeName, L"Mutant" ); + ok( !memcmp( &info[1], &empty_info, sizeof(*info) ), "entry was not cleared\n" );
size = 0xdeadbeef; context = 0xdeadbeef; memset( buffer, 0xcc, sizeof(buffer) ); status = NtQueryDirectoryObject( dir, info, sizeof(*info), FALSE, TRUE, &context, &size ); - todo_wine ok( status == STATUS_MORE_ENTRIES + ok( status == STATUS_MORE_ENTRIES || broken(status == STATUS_BUFFER_TOO_SMALL) /* wow64 */, "got %#lx\n", status ); if (status == STATUS_MORE_ENTRIES) { @@ -2785,7 +2779,7 @@ static void test_query_directory(void) size = 0xdeadbeef; context = 0xdeadbeef; status = NtQueryDirectoryObject( dir, info, 0, FALSE, TRUE, &context, &size ); - todo_wine ok( status == STATUS_MORE_ENTRIES + ok( status == STATUS_MORE_ENTRIES || broken(status == STATUS_BUFFER_TOO_SMALL) /* wow64 */, "got %#lx\n", status ); if (status == STATUS_MORE_ENTRIES) { @@ -2796,14 +2790,11 @@ static void test_query_directory(void) context = 1; memset( buffer, 0xcc, sizeof(buffer) ); status = NtQueryDirectoryObject( dir, info, sizeof(buffer), FALSE, FALSE, &context, &size ); - todo_wine ok( !status, "got %#lx\n", status ); - if (!status) - { - ok( context == 2, "got context %#lx\n", context ); - check_unicode_string( &info[0].ObjectName, name2 ); - check_unicode_string( &info[0].ObjectTypeName, L"Mutant" ); - ok( !memcmp( &info[1], &empty_info, sizeof(*info) ), "entry was not cleared\n" ); - } + ok( !status, "got %#lx\n", status ); + ok( context == 2, "got context %#lx\n", context ); + check_unicode_string( &info[0].ObjectName, name2 ); + check_unicode_string( &info[0].ObjectTypeName, L"Mutant" ); + ok( !memcmp( &info[1], &empty_info, sizeof(*info) ), "entry was not cleared\n" );
pNtClose( child1 ); pNtClose( child2 ); diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index bfbcaf4a851..990c3a40fa9 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -1160,8 +1160,9 @@ NTSTATUS WINAPI NtQueryDirectoryObject( HANDLE handle, DIRECTORY_BASIC_INFORMATI ULONG size, BOOLEAN single_entry, BOOLEAN restart, ULONG *context, ULONG *ret_size ) { + unsigned int status, i, count, pos, used_size, used_count, strpool_head; ULONG index = restart ? 0 : *context; - unsigned int ret; + struct directory_entry *entries;
if (single_entry) { @@ -1171,7 +1172,7 @@ NTSTATUS WINAPI NtQueryDirectoryObject( HANDLE handle, DIRECTORY_BASIC_INFORMATI req->index = index; if (size >= 2 * sizeof(*buffer) + 2 * sizeof(WCHAR)) wine_server_set_reply( req, buffer + 2, size - 2 * sizeof(*buffer) - 2 * sizeof(WCHAR) ); - if (!(ret = wine_server_call( req ))) + if (!(status = wine_server_call( req ))) { buffer->ObjectName.Buffer = (WCHAR *)(buffer + 2); buffer->ObjectName.Length = reply->name_len; @@ -1189,24 +1190,96 @@ NTSTATUS WINAPI NtQueryDirectoryObject( HANDLE handle, DIRECTORY_BASIC_INFORMATI
*context = index + 1; } - else if (ret == STATUS_NO_MORE_ENTRIES) + else if (status == STATUS_NO_MORE_ENTRIES) { if (size > sizeof(*buffer)) memset( buffer, 0, sizeof(*buffer) ); if (ret_size) *ret_size = sizeof(*buffer); }
- if (ret_size && (!ret || ret == STATUS_BUFFER_TOO_SMALL)) + if (ret_size && (!status || status == STATUS_BUFFER_TOO_SMALL)) *ret_size = 2 * sizeof(*buffer) + reply->total_len + 2 * sizeof(WCHAR); } SERVER_END_REQ; + return status; } - else + + if (!(entries = malloc( size ))) return STATUS_NO_MEMORY; + + SERVER_START_REQ( get_directory_entries ) { - FIXME("multiple entries not implemented\n"); - ret = STATUS_NOT_IMPLEMENTED; + req->handle = wine_server_obj_handle( handle ); + req->index = index; + wine_server_set_reply( req, entries, size ); + status = wine_server_call( req ); + count = reply->count; } - return ret; + SERVER_END_REQ; + + if (status && status != STATUS_MORE_ENTRIES) + { + free( entries ); + return status; + } + + used_count = 0; + used_size = sizeof(*buffer); /* "null terminator" entry */ + for (i = pos = 0; i < count; i++) + { + const struct directory_entry *entry = (const struct directory_entry *)((char *)entries + pos); + unsigned int entry_size = sizeof(*buffer) + entry->name_len + entry->type_len + 2 * sizeof(WCHAR); + + if (used_size + entry_size > size) + { + status = STATUS_MORE_ENTRIES; + break; + } + used_count++; + used_size += entry_size; + pos += sizeof(*entry) + ((entry->name_len + entry->type_len + 3) & ~3); + } + + /* + * Avoid making strpool_head a pointer, since it can point beyond end + * of the buffer. Out-of-bounds pointers trigger undefined behavior + * just by existing, even when they are never dereferenced. + */ + strpool_head = sizeof(*buffer) * (used_count + 1); /* after the "null terminator" entry */ + for (i = pos = 0; i < used_count; i++) + { + const struct directory_entry *entry = (const struct directory_entry *)((char *)entries + pos); + + buffer[i].ObjectName.Buffer = (WCHAR *)((char *)buffer + strpool_head); + buffer[i].ObjectName.Length = entry->name_len; + buffer[i].ObjectName.MaximumLength = entry->name_len + sizeof(WCHAR); + memcpy( buffer[i].ObjectName.Buffer, (entry + 1), entry->name_len ); + buffer[i].ObjectName.Buffer[entry->name_len / sizeof(WCHAR)] = 0; + strpool_head += entry->name_len + sizeof(WCHAR); + + buffer[i].ObjectTypeName.Buffer = (WCHAR *)((char *)buffer + strpool_head); + buffer[i].ObjectTypeName.Length = entry->type_len; + buffer[i].ObjectTypeName.MaximumLength = entry->type_len + sizeof(WCHAR); + memcpy( buffer[i].ObjectTypeName.Buffer, (char *)(entry + 1) + entry->name_len, entry->type_len ); + buffer[i].ObjectTypeName.Buffer[entry->type_len / sizeof(WCHAR)] = 0; + strpool_head += entry->type_len + sizeof(WCHAR); + + pos += sizeof(*entry) + ((entry->name_len + entry->type_len + 3) & ~3); + } + + if (size >= sizeof(*buffer)) + memset( &buffer[used_count], 0, sizeof(buffer[used_count]) ); + + free( entries ); + + if (!count && !status) + { + if (ret_size) *ret_size = sizeof(*buffer); + return STATUS_NO_MORE_ENTRIES; + } + + *context = index + used_count; + if (ret_size) *ret_size = strpool_head; + return status; }
diff --git a/server/directory.c b/server/directory.c index fdcfe9bef21..71044ae5bfb 100644 --- a/server/directory.c +++ b/server/directory.c @@ -532,6 +532,81 @@ DECL_HANDLER(open_directory) &directory_ops, &name, req->attributes ); }
+/* get directory entries */ +DECL_HANDLER(get_directory_entries) +{ + struct directory *dir = (struct directory *)get_handle_obj( current->process, req->handle, + DIRECTORY_QUERY, &directory_ops ); + if (dir) + { + struct directory_entry *entry; + struct object *obj; + data_size_t size; + unsigned int i; + char *buffer; + + size = 0; + for (i = 0; ; i++) + { + const struct unicode_str *type_name; + data_size_t name_len; + size_t entry_size; + + if (!(obj = find_object_index( dir->entries, req->index + i ))) + break; + type_name = &obj->ops->type->name; + get_object_name( obj, &name_len ); + entry_size = (sizeof(*entry) + name_len + type_name->len + 3) & ~3; + release_object( obj ); + + if (size + entry_size > get_reply_max_size()) + { + set_error( STATUS_MORE_ENTRIES ); + break; + } + size += entry_size; + } + reply->count = i; + + if (!(buffer = set_reply_data_size( size ))) + { + release_object( dir ); + return; + } + + size = 0; + for (i = 0; i < reply->count; i++) + { + const struct unicode_str *type_name; + data_size_t name_len; + const WCHAR *name; + + obj = find_object_index( dir->entries, req->index + i ); + assert( obj ); + type_name = &obj->ops->type->name; + name = get_object_name( obj, &name_len ); + + entry = (struct directory_entry *)(buffer + size); + entry->name_len = name_len; + entry->type_len = type_name->len; + + size += sizeof(*entry); + memcpy( buffer + size, name, name_len ); + size += name_len; + memcpy( buffer + size, type_name->str, type_name->len ); + size += type_name->len; + if (size & 3) + { + memset( buffer + size, 0, 4 - (size & 3) ); + size += 4 - (size & 3); + } + + release_object( obj ); + } + release_object( dir ); + } +} + /* get a directory entry by index */ DECL_HANDLER(get_directory_entry) { diff --git a/server/protocol.def b/server/protocol.def index e9195df6b65..08cd0cf6d28 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -892,6 +892,14 @@ typedef struct lparam_t info; } cursor_pos_t;
+struct directory_entry +{ + data_size_t name_len; + data_size_t type_len; + /* VARARG(name,unicode_str,name_len); */ + /* VARARG(type,unicode_str,type_len); */ +}; + /****************************************************************/ /* Request declarations */
@@ -3412,6 +3420,16 @@ struct handle_info @END
+/* Get directory entries */ +@REQ(get_directory_entries) + obj_handle_t handle; /* handle to the directory */ + unsigned int index; /* index of first entry */ +@REPLY + unsigned int count; /* number of entries returned */ + VARARG(entries,directory_entries); +@END + + /* Get a directory entry by index */ @REQ(get_directory_entry) obj_handle_t handle; /* handle to the directory */ diff --git a/server/trace.c b/server/trace.c index 55ccefa1746..fa903eb3013 100644 --- a/server/trace.c +++ b/server/trace.c @@ -1383,6 +1383,40 @@ static void dump_varargs_handle_infos( const char *prefix, data_size_t size ) fputc( '}', stderr ); }
+static void dump_varargs_directory_entries( const char *prefix, data_size_t size ) +{ + fprintf( stderr, "%s{", prefix ); + while (size) + { + const struct directory_entry *entry = cur_data; + data_size_t entry_size; + const char *next; + + if (size < sizeof(*entry) || + (size - sizeof(*entry) < entry->name_len) || + (size - sizeof(*entry) - entry->name_len < entry->type_len)) + { + fprintf( stderr, "***invalid***}" ); + remove_data( size ); + return; + } + + next = (const char *)(entry + 1); + fprintf( stderr, "{name=L"" ); + dump_strW( (const WCHAR *)next, entry->name_len, stderr, """" ); + next += entry->name_len; + fprintf( stderr, "",type=L"" ); + dump_strW( (const WCHAR *)next, entry->type_len, stderr, """" ); + fprintf( stderr, ""}" ); + + entry_size = min( size, (sizeof(*entry) + entry->name_len + entry->type_len + 3) & ~3 ); + size -= entry_size; + remove_data( entry_size ); + if (size) fputc( ',', stderr ); + } + fputc( '}', stderr ); +} + typedef void (*dump_func)( const void *req );
/* Everything below this line is generated automatically by tools/make_requests */
From: Zebediah Figura zfigura@codeweavers.com
--- dlls/ntdll/unix/sync.c | 50 ++++++++---------------------------------- server/directory.c | 40 ++++----------------------------- server/protocol.def | 14 ++---------- 3 files changed, 15 insertions(+), 89 deletions(-)
diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 990c3a40fa9..0557ca7a7b2 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -1160,59 +1160,21 @@ NTSTATUS WINAPI NtQueryDirectoryObject( HANDLE handle, DIRECTORY_BASIC_INFORMATI ULONG size, BOOLEAN single_entry, BOOLEAN restart, ULONG *context, ULONG *ret_size ) { - unsigned int status, i, count, pos, used_size, used_count, strpool_head; + unsigned int status, i, count, total_len, pos, used_size, used_count, strpool_head; ULONG index = restart ? 0 : *context; struct directory_entry *entries;
- if (single_entry) - { - SERVER_START_REQ( get_directory_entry ) - { - req->handle = wine_server_obj_handle( handle ); - req->index = index; - if (size >= 2 * sizeof(*buffer) + 2 * sizeof(WCHAR)) - wine_server_set_reply( req, buffer + 2, size - 2 * sizeof(*buffer) - 2 * sizeof(WCHAR) ); - if (!(status = wine_server_call( req ))) - { - buffer->ObjectName.Buffer = (WCHAR *)(buffer + 2); - buffer->ObjectName.Length = reply->name_len; - buffer->ObjectName.MaximumLength = reply->name_len + sizeof(WCHAR); - buffer->ObjectTypeName.Buffer = (WCHAR *)(buffer + 2) + reply->name_len/sizeof(WCHAR) + 1; - buffer->ObjectTypeName.Length = wine_server_reply_size( reply ) - reply->name_len; - buffer->ObjectTypeName.MaximumLength = buffer->ObjectTypeName.Length + sizeof(WCHAR); - /* make room for the terminating null */ - memmove( buffer->ObjectTypeName.Buffer, buffer->ObjectTypeName.Buffer - 1, - buffer->ObjectTypeName.Length ); - buffer->ObjectName.Buffer[buffer->ObjectName.Length/sizeof(WCHAR)] = 0; - buffer->ObjectTypeName.Buffer[buffer->ObjectTypeName.Length/sizeof(WCHAR)] = 0; - - memset( &buffer[1], 0, sizeof(buffer[1]) ); - - *context = index + 1; - } - else if (status == STATUS_NO_MORE_ENTRIES) - { - if (size > sizeof(*buffer)) - memset( buffer, 0, sizeof(*buffer) ); - if (ret_size) *ret_size = sizeof(*buffer); - } - - if (ret_size && (!status || status == STATUS_BUFFER_TOO_SMALL)) - *ret_size = 2 * sizeof(*buffer) + reply->total_len + 2 * sizeof(WCHAR); - } - SERVER_END_REQ; - return status; - } - if (!(entries = malloc( size ))) return STATUS_NO_MEMORY;
SERVER_START_REQ( get_directory_entries ) { req->handle = wine_server_obj_handle( handle ); req->index = index; + req->max_count = single_entry ? 1 : UINT_MAX; wine_server_set_reply( req, entries, size ); status = wine_server_call( req ); count = reply->count; + total_len = reply->total_len; } SERVER_END_REQ;
@@ -1277,6 +1239,12 @@ NTSTATUS WINAPI NtQueryDirectoryObject( HANDLE handle, DIRECTORY_BASIC_INFORMATI return STATUS_NO_MORE_ENTRIES; }
+ if (single_entry && !used_count) + { + if (ret_size) *ret_size = 2 * sizeof(*buffer) + 2 * sizeof(WCHAR) + total_len; + return STATUS_BUFFER_TOO_SMALL; + } + *context = index + used_count; if (ret_size) *ret_size = strpool_head; return status; diff --git a/server/directory.c b/server/directory.c index 71044ae5bfb..6ea149e5011 100644 --- a/server/directory.c +++ b/server/directory.c @@ -545,8 +545,10 @@ DECL_HANDLER(get_directory_entries) unsigned int i; char *buffer;
+ reply->total_len = 0; + size = 0; - for (i = 0; ; i++) + for (i = 0; i < req->max_count; i++) { const struct unicode_str *type_name; data_size_t name_len; @@ -557,6 +559,7 @@ DECL_HANDLER(get_directory_entries) type_name = &obj->ops->type->name; get_object_name( obj, &name_len ); entry_size = (sizeof(*entry) + name_len + type_name->len + 3) & ~3; + reply->total_len += name_len + type_name->len; release_object( obj );
if (size + entry_size > get_reply_max_size()) @@ -607,41 +610,6 @@ DECL_HANDLER(get_directory_entries) } }
-/* get a directory entry by index */ -DECL_HANDLER(get_directory_entry) -{ - struct directory *dir = (struct directory *)get_handle_obj( current->process, req->handle, - DIRECTORY_QUERY, &directory_ops ); - if (dir) - { - struct object *obj = find_object_index( dir->entries, req->index ); - if (obj) - { - data_size_t name_len; - const struct unicode_str *type_name = &obj->ops->type->name; - const WCHAR *name = get_object_name( obj, &name_len ); - - reply->total_len = name_len + type_name->len; - - if (reply->total_len <= get_reply_max_size()) - { - void *ptr = set_reply_data_size( reply->total_len ); - if (ptr) - { - reply->name_len = name_len; - memcpy( ptr, name, name_len ); - memcpy( (char *)ptr + name_len, type_name->str, type_name->len ); - } - } - else set_error( STATUS_BUFFER_TOO_SMALL ); - - release_object( obj ); - } - else set_error( STATUS_NO_MORE_ENTRIES ); - release_object( dir ); - } -} - /* query object type name information */ DECL_HANDLER(get_object_type) { diff --git a/server/protocol.def b/server/protocol.def index 08cd0cf6d28..33108db1861 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3424,24 +3424,14 @@ struct handle_info @REQ(get_directory_entries) obj_handle_t handle; /* handle to the directory */ unsigned int index; /* index of first entry */ + unsigned int max_count; /* maximum number of entries to return */ @REPLY + data_size_t total_len; /* total length needed for strings */ unsigned int count; /* number of entries returned */ VARARG(entries,directory_entries); @END
-/* Get a directory entry by index */ -@REQ(get_directory_entry) - obj_handle_t handle; /* handle to the directory */ - unsigned int index; /* entry index */ -@REPLY - data_size_t total_len; /* total length needed for strings */ - data_size_t name_len; /* length of the entry name in bytes */ - VARARG(name,unicode_str,name_len); /* entry name */ - VARARG(type,unicode_str); /* entry type */ -@END - - /* Create a symbolic link object */ @REQ(create_symlink) unsigned int access; /* access flags */
This merge request was approved by Jinoh Kang.
wouldn't you have to increase the wineserver version when making a change like this, or do you not have to?
On Sat Nov 18 00:34:32 2023 +0000, Etaash Mathamsetty wrote:
wouldn't you have to increase the wineserver protocol version when making a change like this, or do you not have to?
Version bumping is done automatically by `make_requests`. Auto-generated changes should not be a part of a patch proposed for upstream.[^1] [^2]
[^1]: [Wineserver § Help to create a server request](https://wiki.winehq.org/Wineserver#Help_to_create_a_server_request), WineHQ wiki: "As with all generated files, the files generated by make_requests shouldn't be included in your patch. [^2]: [Re: [PATCH] server: Allow skipping debug handle retrieval in get_process_debug_info.](https://www.winehq.org/mailman3/hyperkitty/list/wine-devel@winehq.org/messag...), wine-devel Mailing List Archives: "Also, we do not include automatically generated changes (make_requests) in the patches, they are generated during upstream commit."
On Sat Nov 18 18:08:37 2023 +0000, Jinoh Kang wrote:
Version bumping is done automatically by `make_requests`. Auto-generated changes should not be a part of a patch proposed for upstream.[^1] [^2] [^1]: [Wineserver § Help to create a server request](https://wiki.winehq.org/Wineserver#Help_to_create_a_server_request), WineHQ wiki: "As with all generated files, the files generated by make_requests shouldn't be included in your patch. [^2]: [Re: [PATCH] server: Allow skipping debug handle retrieval in get_process_debug_info.](https://www.winehq.org/mailman3/hyperkitty/list/wine-devel@winehq.org/messag...), wine-devel Mailing List Archives: "Also, we do not include automatically generated changes (make_requests) in the patches, they are generated during upstream commit."
ok thanks for the insight :)
I let this sit because I couldn't immediately find a way to make it less ugly and complicated. This is still similar to my original approach (though splitting out 4/4 arguably helps) but I'm approving anyway since I still don't see a better way to do it.
This merge request was approved by Zebediah Figura.
Anything else I should do, @julliard?