ntdll: Correct implementation for atom query functions.

This commit is contained in:
Eric Pouech 2006-01-03 17:34:43 +01:00 committed by Alexandre Julliard
parent 30086feb44
commit b7607aebdc
6 changed files with 116 additions and 27 deletions

View File

@ -97,6 +97,25 @@ NTSTATUS WINAPI RtlDeleteAtomFromAtomTable( RTL_ATOM_TABLE table, RTL_ATOM atom
return status;
}
/******************************************************************
* integral_atom_name (internal)
*
* Helper for fetching integral (local/global) atoms names.
*/
static ULONG integral_atom_name(WCHAR* buffer, ULONG len, RTL_ATOM atom)
{
static WCHAR fmt[] = {'#','%','u',0};
WCHAR tmp[16];
int ret;
ret = sprintfW( tmp, fmt, atom );
if (!len) return ret * sizeof(WCHAR);
if (len <= ret) ret = len - 1;
memcpy( buffer, tmp, ret * sizeof(WCHAR) );
buffer[ret] = 0;
return ret * sizeof(WCHAR);
}
/******************************************************************
* RtlQueryAtomInAtomTable (NTDLL.@)
*/
@ -104,18 +123,13 @@ NTSTATUS WINAPI RtlQueryAtomInAtomTable( RTL_ATOM_TABLE table, RTL_ATOM atom, UL
ULONG* pin, WCHAR* name, ULONG* len )
{
NTSTATUS status = STATUS_SUCCESS;
WCHAR full_name[MAX_ATOM_LEN];
DWORD wlen = 0;
if (!table) status = STATUS_INVALID_PARAMETER;
else if (atom < MAXINTATOM)
{
if (!atom) return STATUS_INVALID_PARAMETER;
if (len)
{
static WCHAR fmt[] = {'#','%','d',0};
wlen = sprintfW( full_name, fmt, atom ) * sizeof(WCHAR);
}
if (len) wlen = integral_atom_name( name, *len, atom);
if (ref) *ref = 1;
if (pin) *pin = 1;
}
@ -125,11 +139,12 @@ NTSTATUS WINAPI RtlQueryAtomInAtomTable( RTL_ATOM_TABLE table, RTL_ATOM atom, UL
{
req->atom = atom;
req->table = table;
if (len) wine_server_set_reply( req, full_name, sizeof(full_name) );
if (len && *len && name)
wine_server_set_reply( req, name, *len );
status = wine_server_call( req );
if (status == STATUS_SUCCESS)
{
wlen = wine_server_reply_size( reply );
wlen = reply->total;
if (ref) *ref = reply->count;
if (pin) *pin = reply->pinned;
}
@ -138,17 +153,17 @@ NTSTATUS WINAPI RtlQueryAtomInAtomTable( RTL_ATOM_TABLE table, RTL_ATOM atom, UL
}
if (status == STATUS_SUCCESS && len)
{
if (*len > wlen)
if (*len)
{
memcpy( name, full_name, wlen );
name[wlen / sizeof(WCHAR)] = 0;
wlen = min( *len - sizeof(WCHAR), wlen );
if (name) name[wlen / sizeof(WCHAR)] = 0;
}
else status = STATUS_BUFFER_TOO_SMALL;
*len = wlen;
}
TRACE( "%p %x -> %s (%lu)\n",
table, atom, len ? debugstr_w(name) : NULL, status );
TRACE( "%p %x -> %s (%lx)\n",
table, atom, len ? debugstr_wn(name, wlen / sizeof(WCHAR)) : NULL, status );
return status;
}
@ -372,20 +387,20 @@ NTSTATUS WINAPI NtQueryInformationAtom( RTL_ATOM atom, ATOM_INFORMATION_CLASS cl
ULONG name_len;
ATOM_BASIC_INFORMATION* abi = (ATOM_BASIC_INFORMATION*)ptr;
name_len = size - (sizeof(ATOM_BASIC_INFORMATION) - sizeof(WCHAR));
if (size < sizeof(ATOM_BASIC_INFORMATION))
return STATUS_INVALID_PARAMETER;
name_len = size - sizeof(ATOM_BASIC_INFORMATION);
if (atom < MAXINTATOM)
{
if (!atom) status = STATUS_INVALID_PARAMETER;
else if (name_len >= 7 * sizeof(WCHAR))
if (atom)
{
static WCHAR fmt[] = {'#','%','d',0};
abi->NameLength = snprintfW( abi->Name, name_len / sizeof(WCHAR), fmt, atom ) * sizeof(WCHAR);
abi->NameLength = integral_atom_name( abi->Name, name_len, atom );
status = (name_len) ? STATUS_SUCCESS : STATUS_BUFFER_TOO_SMALL;
abi->ReferenceCount = 1;
abi->Pinned = 1;
status = STATUS_SUCCESS;
}
else status = STATUS_BUFFER_TOO_SMALL;
else status = STATUS_INVALID_PARAMETER;
}
else
{
@ -395,19 +410,32 @@ NTSTATUS WINAPI NtQueryInformationAtom( RTL_ATOM atom, ATOM_INFORMATION_CLASS cl
req->table = NULL;
if (name_len) wine_server_set_reply( req, abi->Name, name_len );
status = wine_server_call( req );
name_len = wine_server_reply_size( reply );
if (status == STATUS_SUCCESS)
{
abi->NameLength = name_len;
name_len = wine_server_reply_size( reply );
if (name_len)
{
abi->NameLength = name_len;
abi->Name[name_len / sizeof(WCHAR)] = '\0';
}
else
{
name_len = reply->total;
abi->NameLength = name_len;
status = STATUS_BUFFER_TOO_SMALL;
}
abi->ReferenceCount = reply->count;
abi->Pinned = reply->pinned;
}
else name_len = 0;
}
SERVER_END_REQ;
}
TRACE( "%x -> %s (%lu)\n", atom, debugstr_wn(abi->Name, name_len/sizeof(WCHAR)), status );
TRACE( "%x -> %s (%lu)\n",
atom, debugstr_wn(abi->Name, abi->NameLength / sizeof(WCHAR)),
status );
if (psize)
*psize = sizeof(ATOM_BASIC_INFORMATION) - sizeof(WCHAR) + name_len;
*psize = sizeof(ATOM_BASIC_INFORMATION) + name_len;
}
break;
default:

View File

@ -54,6 +54,9 @@ static NTSTATUS (WINAPI *pRtlLookupAtomInAtomTable)(RTL_ATOM_TABLE,PCWSTR,PRTL_A
static NTSTATUS (WINAPI *pRtlPinAtomInAtomTable)(RTL_ATOM_TABLE,RTL_ATOM);
static NTSTATUS (WINAPI *pRtlQueryAtomInAtomTable)(RTL_ATOM_TABLE,RTL_ATOM,PULONG,PULONG,PWSTR,PULONG);
static NTSTATUS (WINAPI* pNtAddAtom)(LPCWSTR,ULONG,RTL_ATOM*);
static NTSTATUS (WINAPI* pNtQueryInformationAtom)(RTL_ATOM,DWORD,void*,ULONG,PULONG);
static const WCHAR EmptyAtom[] = {0};
static const WCHAR testAtom1[] = {'H','e','l','l','o',' ','W','o','r','l','d',0};
static const WCHAR testAtom2[] = {'H','e','l','l','o',' ','W','o','r','l','d','2',0};
@ -81,6 +84,9 @@ static void InitFunctionPtr(void)
pRtlLookupAtomInAtomTable = (void *)GetProcAddress(hntdll, "RtlLookupAtomInAtomTable");
pRtlPinAtomInAtomTable = (void *)GetProcAddress(hntdll, "RtlPinAtomInAtomTable");
pRtlQueryAtomInAtomTable = (void *)GetProcAddress(hntdll, "RtlQueryAtomInAtomTable");
pNtAddAtom = (void *)GetProcAddress(hntdll, "NtAddAtom");
pNtQueryInformationAtom = (void *)GetProcAddress(hntdll, "NtQueryInformationAtom");
}
}
@ -192,6 +198,15 @@ static void test_NtAtom(void)
ok(!strcmpW(Name, testAtom2), "We found wrong atom\n");
ok((strlenW(testAtom2) * sizeof(WCHAR)) == Len, "Returned wrong length %ld\n", Len);
Len = 8;
Name[0] = Name[1] = Name[2] = Name[3] = Name[4] = 0x55AA;
res = pRtlQueryAtomInAtomTable(AtomTable, Atom2, NULL, NULL, Name, &Len);
ok(!res, "query atom %lx\n", res);
ok(Len == 6, "wrong length %lu\n", Len);
ok(!memcmp(Name, testAtom2, Len), "wrong atom string\n");
ok(!Name[3], "wrong string termination\n");
ok(Name[4] == 0x55AA, "buffer overwrite\n");
res = pRtlLookupAtomInAtomTable(AtomTable, testAtom2, &testAtom);
ok(!res, "We can't find our pinned atom!! retval: %lx\n", res);
ok(testAtom == Atom2, "We found wrong atom!!!\n");
@ -402,6 +417,47 @@ static void test_NtRefPinAtom(void)
}
}
static void test_Global(void)
{
NTSTATUS res;
RTL_ATOM atom;
char ptr[sizeof(ATOM_BASIC_INFORMATION) + 255 * sizeof(WCHAR)];
ATOM_BASIC_INFORMATION* abi = (ATOM_BASIC_INFORMATION*)ptr;
ULONG ptr_size = sizeof(ATOM_BASIC_INFORMATION) + 255 * sizeof(WCHAR);
res = pNtAddAtom(testAtom1, lstrlenW(testAtom1) * sizeof(WCHAR), &atom);
ok(!res, "Added atom (%lx)\n", res);
memset(abi->Name, 0x55, 255 * sizeof(WCHAR));
res = pNtQueryInformationAtom( atom, AtomBasicInformation, (void*)ptr, ptr_size, NULL );
ok(!res, "atom lookup\n");
ok(!lstrcmpW(abi->Name, testAtom1), "ok strings\n");
ok(abi->NameLength == lstrlenW(testAtom1) * sizeof(WCHAR), "wrong string length\n");
ok(abi->Name[lstrlenW(testAtom1)] == 0, "wrong string termination %x\n", abi->Name[lstrlenW(testAtom1)]);
ok(abi->Name[lstrlenW(testAtom1) + 1] == 0x5555, "buffer overwrite %x\n", abi->Name[lstrlenW(testAtom1) + 1]);
ptr_size = sizeof(ATOM_BASIC_INFORMATION);
res = pNtQueryInformationAtom( atom, AtomBasicInformation, (void*)ptr, ptr_size, NULL );
ok(res == STATUS_BUFFER_TOO_SMALL, "wrong return status (%lx)\n", res);
ok(abi->NameLength == lstrlenW(testAtom1) * sizeof(WCHAR), "ok string length\n");
memset(abi->Name, 0x55, lstrlenW(testAtom1) * sizeof(WCHAR));
ptr_size = sizeof(ATOM_BASIC_INFORMATION) + lstrlenW(testAtom1) * sizeof(WCHAR);
res = pNtQueryInformationAtom( atom, AtomBasicInformation, (void*)ptr, ptr_size, NULL );
ok(!res, "atom lookup %lx\n", res);
ok(!lstrcmpW(abi->Name, testAtom1), "strings don't match\n");
ok(abi->NameLength == lstrlenW(testAtom1) * sizeof(WCHAR), "wrong string length\n");
ok(abi->Name[lstrlenW(testAtom1)] == 0, "buffer overwrite %x\n", abi->Name[lstrlenW(testAtom1)]);
ok(abi->Name[lstrlenW(testAtom1) + 1] == 0x5555, "buffer overwrite %x\n", abi->Name[lstrlenW(testAtom1) + 1]);
ptr_size = sizeof(ATOM_BASIC_INFORMATION) + 4 * sizeof(WCHAR);
abi->Name[0] = abi->Name[1] = abi->Name[2] = abi->Name[3] = '\0';
res = pNtQueryInformationAtom( atom, AtomBasicInformation, (void*)ptr, ptr_size, NULL );
ok(!res, "couldn't find atom\n");
ok(abi->NameLength == 8, "wrong string length %u\n", abi->NameLength);
ok(!memcmp(abi->Name, testAtom1, 8), "strings don't match\n");
}
START_TEST(atom)
{
InitFunctionPtr();
@ -410,5 +466,6 @@ START_TEST(atom)
test_NtAtom();
test_NtIntAtom();
test_NtRefPinAtom();
test_Global();
}
}

View File

@ -2078,6 +2078,7 @@ struct get_atom_information_reply
struct reply_header __header;
int count;
int pinned;
size_t total;
/* VARARG(name,unicode_str); */
};
@ -4346,6 +4347,6 @@ union generic_reply
struct query_symlink_reply query_symlink_reply;
};
#define SERVER_PROTOCOL_VERSION 217
#define SERVER_PROTOCOL_VERSION 218
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */

View File

@ -413,10 +413,11 @@ DECL_HANDLER(get_atom_information)
if ((entry = get_atom_entry( table, req->atom )))
{
size_t len = entry->len * sizeof(WCHAR);
if (len <= get_reply_max_size()) set_reply_data( entry->str, len );
else if (get_reply_max_size()) set_error( STATUS_BUFFER_OVERFLOW );
if (get_reply_max_size())
set_reply_data( entry->str, min( len, get_reply_max_size()));
reply->count = entry->count;
reply->pinned = entry->pinned;
reply->total = len;
}
else reply->count = -1;
release_object( table );

View File

@ -1488,6 +1488,7 @@ enum char_info_mode
@REPLY
int count; /* atom lock count */
int pinned; /* whether the atom has been pinned */
size_t total; /* actual length of atom name */
VARARG(name,unicode_str); /* atom name */
@END

View File

@ -1961,6 +1961,7 @@ static void dump_get_atom_information_reply( const struct get_atom_information_r
{
fprintf( stderr, " count=%d,", req->count );
fprintf( stderr, " pinned=%d,", req->pinned );
fprintf( stderr, " total=%d,", req->total );
fprintf( stderr, " name=" );
dump_varargs_unicode_str( cur_size );
}