ntdll: Add tests for buffer overflows in NtQueryDirectoryFile.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
b0ce049cbb
commit
a4dcfd1195
|
@ -2225,6 +2225,7 @@ NTSTATUS WINAPI NtQueryDirectoryFile( HANDLE handle, HANDLE event,
|
||||||
BOOLEAN restart_scan )
|
BOOLEAN restart_scan )
|
||||||
{
|
{
|
||||||
int cwd, fd, needs_close;
|
int cwd, fd, needs_close;
|
||||||
|
NTSTATUS status;
|
||||||
|
|
||||||
TRACE("(%p %p %p %p %p %p 0x%08x 0x%08x 0x%08x %s 0x%08x\n",
|
TRACE("(%p %p %p %p %p %p 0x%08x 0x%08x 0x%08x %s 0x%08x\n",
|
||||||
handle, event, apc_routine, apc_context, io, buffer,
|
handle, event, apc_routine, apc_context, io, buffer,
|
||||||
|
@ -2234,7 +2235,7 @@ NTSTATUS WINAPI NtQueryDirectoryFile( HANDLE handle, HANDLE event,
|
||||||
if (event || apc_routine)
|
if (event || apc_routine)
|
||||||
{
|
{
|
||||||
FIXME( "Unsupported yet option\n" );
|
FIXME( "Unsupported yet option\n" );
|
||||||
return io->u.Status = STATUS_NOT_IMPLEMENTED;
|
return STATUS_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
switch (info_class)
|
switch (info_class)
|
||||||
{
|
{
|
||||||
|
@ -2243,16 +2244,16 @@ NTSTATUS WINAPI NtQueryDirectoryFile( HANDLE handle, HANDLE event,
|
||||||
case FileFullDirectoryInformation:
|
case FileFullDirectoryInformation:
|
||||||
case FileIdBothDirectoryInformation:
|
case FileIdBothDirectoryInformation:
|
||||||
case FileIdFullDirectoryInformation:
|
case FileIdFullDirectoryInformation:
|
||||||
if (length < dir_info_size( info_class, 1 )) return io->u.Status = STATUS_INFO_LENGTH_MISMATCH;
|
if (length < dir_info_size( info_class, 1 )) return STATUS_INFO_LENGTH_MISMATCH;
|
||||||
if (!buffer) return io->u.Status = STATUS_ACCESS_VIOLATION;
|
if (!buffer) return STATUS_ACCESS_VIOLATION;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
FIXME( "Unsupported file info class %d\n", info_class );
|
FIXME( "Unsupported file info class %d\n", info_class );
|
||||||
return io->u.Status = STATUS_NOT_IMPLEMENTED;
|
return STATUS_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((io->u.Status = server_get_unix_fd( handle, FILE_LIST_DIRECTORY, &fd, &needs_close, NULL, NULL )) != STATUS_SUCCESS)
|
if ((status = server_get_unix_fd( handle, FILE_LIST_DIRECTORY, &fd, &needs_close, NULL, NULL )) != STATUS_SUCCESS)
|
||||||
return io->u.Status;
|
return status;
|
||||||
|
|
||||||
io->Information = 0;
|
io->Information = 0;
|
||||||
|
|
||||||
|
@ -2290,16 +2291,17 @@ NTSTATUS WINAPI NtQueryDirectoryFile( HANDLE handle, HANDLE event,
|
||||||
read_directory_readdir( fd, io, buffer, length, single_entry, mask, restart_scan, info_class );
|
read_directory_readdir( fd, io, buffer, length, single_entry, mask, restart_scan, info_class );
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
status = io->u.Status;
|
||||||
if (cwd == -1 || fchdir( cwd ) == -1) chdir( "/" );
|
if (cwd == -1 || fchdir( cwd ) == -1) chdir( "/" );
|
||||||
}
|
}
|
||||||
else io->u.Status = FILE_GetNtStatus();
|
else status = FILE_GetNtStatus();
|
||||||
|
|
||||||
RtlLeaveCriticalSection( &dir_section );
|
RtlLeaveCriticalSection( &dir_section );
|
||||||
|
|
||||||
if (needs_close) close( fd );
|
if (needs_close) close( fd );
|
||||||
if (cwd != -1) close( cwd );
|
if (cwd != -1) close( cwd );
|
||||||
TRACE( "=> %x (%ld)\n", io->u.Status, io->Information );
|
TRACE( "=> %x (%ld)\n", status, io->Information );
|
||||||
return io->u.Status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -168,7 +168,7 @@ static void test_flags_NtQueryDirectoryFile(OBJECT_ATTRIBUTES *attr, const char
|
||||||
UINT data_len; /* length of dir data */
|
UINT data_len; /* length of dir data */
|
||||||
BYTE data[8192]; /* directory data */
|
BYTE data[8192]; /* directory data */
|
||||||
FILE_BOTH_DIRECTORY_INFORMATION *dir_info;
|
FILE_BOTH_DIRECTORY_INFORMATION *dir_info;
|
||||||
DWORD status;
|
NTSTATUS status;
|
||||||
int numfiles;
|
int numfiles;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -185,8 +185,10 @@ static void test_flags_NtQueryDirectoryFile(OBJECT_ATTRIBUTES *attr, const char
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pNtQueryDirectoryFile( dirh, NULL, NULL, NULL, &io, data, data_size,
|
U(io).Status = 0xdeadbeef;
|
||||||
FileBothDirectoryInformation, single_entry, mask, restart_flag );
|
status = pNtQueryDirectoryFile( dirh, NULL, NULL, NULL, &io, data, data_size,
|
||||||
|
FileBothDirectoryInformation, single_entry, mask, restart_flag );
|
||||||
|
ok (status == STATUS_SUCCESS, "failed to query directory; status %x\n", status);
|
||||||
ok (U(io).Status == STATUS_SUCCESS, "failed to query directory; status %x\n", U(io).Status);
|
ok (U(io).Status == STATUS_SUCCESS, "failed to query directory; status %x\n", U(io).Status);
|
||||||
data_len = io.Information;
|
data_len = io.Information;
|
||||||
ok (data_len >= sizeof(FILE_BOTH_DIRECTORY_INFORMATION), "not enough data in directory\n");
|
ok (data_len >= sizeof(FILE_BOTH_DIRECTORY_INFORMATION), "not enough data in directory\n");
|
||||||
|
@ -199,11 +201,12 @@ static void test_flags_NtQueryDirectoryFile(OBJECT_ATTRIBUTES *attr, const char
|
||||||
tally_test_file(dir_info);
|
tally_test_file(dir_info);
|
||||||
|
|
||||||
if (dir_info->NextEntryOffset == 0) {
|
if (dir_info->NextEntryOffset == 0) {
|
||||||
pNtQueryDirectoryFile( dirh, 0, NULL, NULL, &io, data, data_size,
|
U(io).Status = 0xdeadbeef;
|
||||||
FileBothDirectoryInformation, single_entry, mask, FALSE );
|
status = pNtQueryDirectoryFile( dirh, 0, NULL, NULL, &io, data, data_size,
|
||||||
if (U(io).Status == STATUS_NO_MORE_FILES)
|
FileBothDirectoryInformation, single_entry, mask, FALSE );
|
||||||
break;
|
ok (U(io).Status == status, "wrong status %x / %x\n", status, U(io).Status);
|
||||||
ok (U(io).Status == STATUS_SUCCESS, "failed to query directory; status %x\n", U(io).Status);
|
if (status == STATUS_NO_MORE_FILES) break;
|
||||||
|
ok (status == STATUS_SUCCESS, "failed to query directory; status %x\n", status);
|
||||||
data_len = io.Information;
|
data_len = io.Information;
|
||||||
if (data_len < sizeof(FILE_BOTH_DIRECTORY_INFORMATION))
|
if (data_len < sizeof(FILE_BOTH_DIRECTORY_INFORMATION))
|
||||||
break;
|
break;
|
||||||
|
@ -239,8 +242,9 @@ static void test_NtQueryDirectoryFile(void)
|
||||||
WCHAR short_name[12];
|
WCHAR short_name[12];
|
||||||
UINT data_size;
|
UINT data_size;
|
||||||
BYTE data[8192];
|
BYTE data[8192];
|
||||||
FILE_BOTH_DIRECTORY_INFORMATION *fbdi = (FILE_BOTH_DIRECTORY_INFORMATION*)data;
|
FILE_BOTH_DIRECTORY_INFORMATION *next, *fbdi = (FILE_BOTH_DIRECTORY_INFORMATION*)data;
|
||||||
DWORD status;
|
const WCHAR *filename = fbdi->FileName;
|
||||||
|
NTSTATUS status;
|
||||||
HANDLE dirh;
|
HANDLE dirh;
|
||||||
|
|
||||||
/* Clean up from prior aborted run, if any, then set up test files */
|
/* Clean up from prior aborted run, if any, then set up test files */
|
||||||
|
@ -284,24 +288,152 @@ static void test_NtQueryDirectoryFile(void)
|
||||||
mask.Buffer = testfiles[0].nameW;
|
mask.Buffer = testfiles[0].nameW;
|
||||||
mask.Length = mask.MaximumLength = lstrlenW(testfiles[0].nameW) * sizeof(WCHAR);
|
mask.Length = mask.MaximumLength = lstrlenW(testfiles[0].nameW) * sizeof(WCHAR);
|
||||||
data_size = offsetof(FILE_BOTH_DIRECTORY_INFORMATION, FileName[256]);
|
data_size = offsetof(FILE_BOTH_DIRECTORY_INFORMATION, FileName[256]);
|
||||||
pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size,
|
U(io).Status = 0xdeadbeef;
|
||||||
FileBothDirectoryInformation, TRUE, &mask, FALSE);
|
status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size,
|
||||||
|
FileBothDirectoryInformation, TRUE, &mask, FALSE);
|
||||||
|
ok(status == STATUS_SUCCESS, "failed to query directory; status %x\n", status);
|
||||||
ok(U(io).Status == STATUS_SUCCESS, "failed to query directory; status %x\n", U(io).Status);
|
ok(U(io).Status == STATUS_SUCCESS, "failed to query directory; status %x\n", U(io).Status);
|
||||||
ok(fbdi->ShortName[0], "ShortName is empty\n");
|
ok(fbdi->ShortName[0], "ShortName is empty\n");
|
||||||
|
|
||||||
mask.Length = mask.MaximumLength = fbdi->ShortNameLength;
|
mask.Length = mask.MaximumLength = fbdi->ShortNameLength;
|
||||||
memcpy(short_name, fbdi->ShortName, mask.Length);
|
memcpy(short_name, fbdi->ShortName, mask.Length);
|
||||||
mask.Buffer = short_name;
|
mask.Buffer = short_name;
|
||||||
pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size,
|
U(io).Status = 0xdeadbeef;
|
||||||
FileBothDirectoryInformation, TRUE, &mask, TRUE);
|
U(io).Information = 0xdeadbeef;
|
||||||
|
status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size,
|
||||||
|
FileBothDirectoryInformation, TRUE, &mask, TRUE);
|
||||||
|
ok(status == STATUS_SUCCESS, "failed to query directory status %x\n", status);
|
||||||
ok(U(io).Status == STATUS_SUCCESS, "failed to query directory status %x\n", U(io).Status);
|
ok(U(io).Status == STATUS_SUCCESS, "failed to query directory status %x\n", U(io).Status);
|
||||||
|
todo_wine
|
||||||
|
ok(U(io).Information == offsetof(FILE_BOTH_DIRECTORY_INFORMATION, FileName[strlen(testfiles[0].name)]),
|
||||||
|
"wrong info %lx\n", U(io).Information);
|
||||||
ok(fbdi->FileNameLength == strlen(testfiles[0].name)*sizeof(WCHAR) &&
|
ok(fbdi->FileNameLength == strlen(testfiles[0].name)*sizeof(WCHAR) &&
|
||||||
!memcmp(fbdi->FileName, testfiles[0].nameW, fbdi->FileNameLength),
|
!memcmp(fbdi->FileName, testfiles[0].nameW, fbdi->FileNameLength),
|
||||||
"incorrect long file name: %s\n", wine_dbgstr_wn(fbdi->FileName,
|
"incorrect long file name: %s\n", wine_dbgstr_wn(fbdi->FileName,
|
||||||
fbdi->FileNameLength/sizeof(WCHAR)));
|
fbdi->FileNameLength/sizeof(WCHAR)));
|
||||||
|
|
||||||
|
/* tests with short buffer */
|
||||||
|
memset( data, 0x55, data_size );
|
||||||
|
U(io).Status = 0xdeadbeef;
|
||||||
|
U(io).Information = 0xdeadbeef;
|
||||||
|
data_size = offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] );
|
||||||
|
status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size,
|
||||||
|
FileBothDirectoryInformation, TRUE, &mask, TRUE);
|
||||||
|
ok( status == STATUS_BUFFER_OVERFLOW, "wrong status %x\n", status );
|
||||||
|
ok( U(io).Status == STATUS_BUFFER_OVERFLOW, "wrong status %x\n", U(io).Status );
|
||||||
|
ok( U(io).Information == offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ),
|
||||||
|
"wrong info %lx\n", U(io).Information );
|
||||||
|
ok( fbdi->NextEntryOffset == 0, "wrong offset %x\n", fbdi->NextEntryOffset );
|
||||||
|
ok( fbdi->FileNameLength == strlen(testfiles[0].name) * sizeof(WCHAR),
|
||||||
|
"wrong length %x\n", fbdi->FileNameLength );
|
||||||
|
ok( filename[0] == testfiles[0].nameW[0], "incorrect long file name: %s\n",
|
||||||
|
wine_dbgstr_wn(fbdi->FileName, fbdi->FileNameLength/sizeof(WCHAR)));
|
||||||
|
todo_wine
|
||||||
|
ok( filename[1] == 0x5555, "incorrect long file name: %s\n",
|
||||||
|
wine_dbgstr_wn(fbdi->FileName, fbdi->FileNameLength/sizeof(WCHAR)));
|
||||||
|
|
||||||
|
memset( data, 0x55, data_size );
|
||||||
|
U(io).Status = 0xdeadbeef;
|
||||||
|
U(io).Information = 0xdeadbeef;
|
||||||
|
data_size = offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[0] );
|
||||||
|
status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size,
|
||||||
|
FileBothDirectoryInformation, FALSE, &mask, TRUE);
|
||||||
|
ok( status == STATUS_INFO_LENGTH_MISMATCH, "weong status %x\n", status );
|
||||||
|
ok( U(io).Status == 0xdeadbeef, "wrong status %x\n", U(io).Status );
|
||||||
|
ok( U(io).Information == 0xdeadbeef, "wrong info %lx\n", U(io).Information );
|
||||||
|
ok( fbdi->NextEntryOffset == 0x55555555, "wrong offset %x\n", fbdi->NextEntryOffset );
|
||||||
|
|
||||||
pNtClose(dirh);
|
pNtClose(dirh);
|
||||||
|
|
||||||
|
status = pNtOpenFile(&dirh, SYNCHRONIZE | FILE_LIST_DIRECTORY, &attr, &io, FILE_SHARE_READ,
|
||||||
|
FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_DIRECTORY_FILE);
|
||||||
|
ok(status == STATUS_SUCCESS, "failed to open dir '%s'\n", testdirA);
|
||||||
|
|
||||||
|
memset( data, 0x55, data_size );
|
||||||
|
data_size = sizeof(data);
|
||||||
|
U(io).Status = 0xdeadbeef;
|
||||||
|
U(io).Information = 0xdeadbeef;
|
||||||
|
status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size,
|
||||||
|
FileBothDirectoryInformation, FALSE, NULL, TRUE);
|
||||||
|
ok(status == STATUS_SUCCESS, "wrong status %x\n", status);
|
||||||
|
ok(U(io).Status == STATUS_SUCCESS, "wrong status %x\n", U(io).Status);
|
||||||
|
ok(U(io).Information > 0 && U(io).Information < data_size, "wrong info %lx\n", U(io).Information);
|
||||||
|
ok( fbdi->NextEntryOffset == ((offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ) + 7) & ~7),
|
||||||
|
"wrong offset %x\n", fbdi->NextEntryOffset );
|
||||||
|
ok( fbdi->FileNameLength == sizeof(WCHAR), "wrong length %x\n", fbdi->FileNameLength );
|
||||||
|
ok( fbdi->FileName[0] == '.', "incorrect long file name: %s\n",
|
||||||
|
wine_dbgstr_wn(fbdi->FileName, fbdi->FileNameLength/sizeof(WCHAR)));
|
||||||
|
next = (FILE_BOTH_DIRECTORY_INFORMATION *)(data + fbdi->NextEntryOffset);
|
||||||
|
ok( next->NextEntryOffset == ((offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[2] ) + 7) & ~7),
|
||||||
|
"wrong offset %x\n", next->NextEntryOffset );
|
||||||
|
ok( next->FileNameLength == 2 * sizeof(WCHAR), "wrong length %x\n", next->FileNameLength );
|
||||||
|
filename = next->FileName;
|
||||||
|
ok( filename[0] == '.' && filename[1] == '.', "incorrect long file name: %s\n",
|
||||||
|
wine_dbgstr_wn(next->FileName, next->FileNameLength/sizeof(WCHAR)));
|
||||||
|
|
||||||
|
data_size = fbdi->NextEntryOffset + offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ),
|
||||||
|
memset( data, 0x55, data_size );
|
||||||
|
U(io).Status = 0xdeadbeef;
|
||||||
|
U(io).Information = 0xdeadbeef;
|
||||||
|
status = pNtQueryDirectoryFile( dirh, 0, NULL, NULL, &io, data, data_size,
|
||||||
|
FileBothDirectoryInformation, FALSE, NULL, TRUE );
|
||||||
|
ok( status == STATUS_SUCCESS, "wrong status %x\n", status );
|
||||||
|
ok( U(io).Status == STATUS_SUCCESS, "wrong status %x\n", U(io).Status );
|
||||||
|
ok( U(io).Information == offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ),
|
||||||
|
"wrong info %lx\n", U(io).Information );
|
||||||
|
ok( fbdi->NextEntryOffset == 0, "wrong offset %x\n", fbdi->NextEntryOffset );
|
||||||
|
ok( fbdi->FileNameLength == sizeof(WCHAR), "wrong length %x\n", fbdi->FileNameLength );
|
||||||
|
ok( fbdi->FileName[0] == '.', "incorrect long file name: %s\n",
|
||||||
|
wine_dbgstr_wn(fbdi->FileName, fbdi->FileNameLength/sizeof(WCHAR)));
|
||||||
|
next = (FILE_BOTH_DIRECTORY_INFORMATION *)&fbdi->FileName[1];
|
||||||
|
ok( next->NextEntryOffset == 0x55555555, "wrong offset %x\n", next->NextEntryOffset );
|
||||||
|
|
||||||
|
data_size = fbdi->NextEntryOffset + offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[2] ),
|
||||||
|
memset( data, 0x55, data_size );
|
||||||
|
U(io).Status = 0xdeadbeef;
|
||||||
|
U(io).Information = 0xdeadbeef;
|
||||||
|
status = pNtQueryDirectoryFile( dirh, 0, NULL, NULL, &io, data, data_size,
|
||||||
|
FileBothDirectoryInformation, FALSE, NULL, TRUE );
|
||||||
|
ok( status == STATUS_SUCCESS, "wrong status %x\n", status );
|
||||||
|
ok( U(io).Status == STATUS_SUCCESS, "wrong status %x\n", U(io).Status );
|
||||||
|
ok( U(io).Information == offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ),
|
||||||
|
"wrong info %lx\n", U(io).Information );
|
||||||
|
ok( fbdi->NextEntryOffset == 0, "wrong offset %x\n", fbdi->NextEntryOffset );
|
||||||
|
|
||||||
|
data_size = ((offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ) + 7) & ~7) +
|
||||||
|
offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[2] );
|
||||||
|
memset( data, 0x55, data_size );
|
||||||
|
U(io).Status = 0xdeadbeef;
|
||||||
|
U(io).Information = 0xdeadbeef;
|
||||||
|
status = pNtQueryDirectoryFile( dirh, 0, NULL, NULL, &io, data, data_size,
|
||||||
|
FileBothDirectoryInformation, FALSE, NULL, TRUE );
|
||||||
|
ok( status == STATUS_SUCCESS, "wrong status %x\n", status );
|
||||||
|
ok( U(io).Status == STATUS_SUCCESS, "wrong status %x\n", U(io).Status );
|
||||||
|
todo_wine
|
||||||
|
ok( U(io).Information == data_size, "wrong info %lx / %x\n", U(io).Information, data_size );
|
||||||
|
todo_wine
|
||||||
|
ok( fbdi->NextEntryOffset == ((offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ) + 7) & ~7),
|
||||||
|
"wrong offset %x\n", fbdi->NextEntryOffset );
|
||||||
|
ok( fbdi->FileNameLength == sizeof(WCHAR), "wrong length %x\n", fbdi->FileNameLength );
|
||||||
|
ok( fbdi->FileName[0] == '.', "incorrect long file name: %s\n",
|
||||||
|
wine_dbgstr_wn(fbdi->FileName, fbdi->FileNameLength/sizeof(WCHAR)));
|
||||||
|
next = (FILE_BOTH_DIRECTORY_INFORMATION *)(data + fbdi->NextEntryOffset);
|
||||||
|
ok( next->NextEntryOffset == 0, "wrong offset %x\n", next->NextEntryOffset );
|
||||||
|
todo_wine
|
||||||
|
ok( next->FileNameLength == 2 * sizeof(WCHAR), "wrong length %x\n", next->FileNameLength );
|
||||||
|
filename = next->FileName;
|
||||||
|
todo_wine
|
||||||
|
ok( filename[0] == '.' && filename[1] == '.', "incorrect long file name: %s\n",
|
||||||
|
wine_dbgstr_wn(next->FileName, next->FileNameLength/sizeof(WCHAR)));
|
||||||
|
|
||||||
|
pNtClose(dirh);
|
||||||
|
|
||||||
|
U(io).Status = 0xdeadbeef;
|
||||||
|
status = pNtQueryDirectoryFile( (HANDLE)0xbeef, 0, NULL, NULL, &io, data, data_size,
|
||||||
|
FileBothDirectoryInformation, TRUE, NULL, TRUE );
|
||||||
|
ok(status == STATUS_INVALID_HANDLE, "wrong status %x\n", status);
|
||||||
|
ok(U(io).Status == 0xdeadbeef, "wrong status %x\n", U(io).Status);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
tear_down_attribute_test(testdirA);
|
tear_down_attribute_test(testdirA);
|
||||||
pRtlFreeUnicodeString(&ntdirname);
|
pRtlFreeUnicodeString(&ntdirname);
|
||||||
|
|
Loading…
Reference in New Issue