[PATCH] kernel32: implemented "Basic" mode of findfirstfilex
Marcus Meissner
marcus at jet.franken.de
Sun Mar 23 09:08:33 CDT 2014
FindExInfoBasic was not handled, rewrite it a bit to handle it.
---
dlls/kernel32/file.c | 112 +++++++++++++++++++++++++++++----------------
dlls/kernel32/tests/file.c | 42 +++++++++++++++++
2 files changed, 115 insertions(+), 39 deletions(-)
diff --git a/dlls/kernel32/file.c b/dlls/kernel32/file.c
index e205050..e986110 100644
--- a/dlls/kernel32/file.c
+++ b/dlls/kernel32/file.c
@@ -57,6 +57,7 @@ typedef struct
HANDLE handle; /* handle to directory */
CRITICAL_SECTION cs; /* crit section protecting this structure */
FINDEX_SEARCH_OPS search_op; /* Flags passed to FindFirst. */
+ FILE_INFORMATION_CLASS infoclass; /* information requested */
UNICODE_STRING mask; /* file mask */
UNICODE_STRING path; /* NT path used to open the directory */
BOOL is_root; /* is directory the root of the drive? */
@@ -118,7 +119,7 @@ static HANDLE create_file_OF( LPCSTR path, INT mode )
*
* Check if a dir symlink should be returned by FindNextFile.
*/
-static BOOL check_dir_symlink( FIND_FIRST_INFO *info, const FILE_BOTH_DIR_INFORMATION *file_info )
+static BOOL check_dir_symlink( FIND_FIRST_INFO *info, ULONG FileNameLength, WCHAR *FileName )
{
UNICODE_STRING str;
ANSI_STRING unix_name;
@@ -126,13 +127,13 @@ static BOOL check_dir_symlink( FIND_FIRST_INFO *info, const FILE_BOTH_DIR_INFORM
BOOL ret = TRUE;
DWORD len;
- str.MaximumLength = info->path.Length + sizeof(WCHAR) + file_info->FileNameLength;
+ str.MaximumLength = info->path.Length + sizeof(WCHAR) + FileNameLength;
if (!(str.Buffer = HeapAlloc( GetProcessHeap(), 0, str.MaximumLength ))) return TRUE;
memcpy( str.Buffer, info->path.Buffer, info->path.Length );
len = info->path.Length / sizeof(WCHAR);
if (!len || str.Buffer[len-1] != '\\') str.Buffer[len++] = '\\';
- memcpy( str.Buffer + len, file_info->FileName, file_info->FileNameLength );
- str.Length = len * sizeof(WCHAR) + file_info->FileNameLength;
+ memcpy( str.Buffer + len, FileName, FileNameLength );
+ str.Length = len * sizeof(WCHAR) + FileNameLength;
unix_name.Buffer = NULL;
if (!wine_nt_to_unix_file_name( &str, &unix_name, OPEN_EXISTING, FALSE ) &&
@@ -1858,6 +1859,7 @@ HANDLE WINAPI FindFirstFileExW( LPCWSTR filename, FINDEX_INFO_LEVELS level,
IO_STATUS_BLOCK io;
NTSTATUS status;
DWORD device = 0;
+ FILE_INFORMATION_CLASS infoclass;
TRACE("%s %d %p %d %p %x\n", debugstr_w(filename), level, data, search_op, filter, flags);
@@ -1867,8 +1869,14 @@ HANDLE WINAPI FindFirstFileExW( LPCWSTR filename, FINDEX_INFO_LEVELS level,
FIXME("options not implemented 0x%08x 0x%08x\n", search_op, flags );
return INVALID_HANDLE_VALUE;
}
- if (level != FindExInfoStandard)
- {
+ switch (level) {
+ case FindExInfoStandard:
+ infoclass = FileBothDirectoryInformation;
+ break;
+ case FindExInfoBasic:
+ infoclass = FileFullDirectoryInformation;
+ break;
+ default:
FIXME("info level %d not implemented\n", level );
return INVALID_HANDLE_VALUE;
}
@@ -1970,6 +1978,7 @@ HANDLE WINAPI FindFirstFileExW( LPCWSTR filename, FINDEX_INFO_LEVELS level,
info->data_size = 0;
info->data = NULL;
info->search_op = search_op;
+ info->infoclass = infoclass;
if (device)
{
@@ -1998,7 +2007,7 @@ HANDLE WINAPI FindFirstFileExW( LPCWSTR filename, FINDEX_INFO_LEVELS level,
}
NtQueryDirectoryFile( info->handle, 0, NULL, NULL, &io, info->data, info->data_size,
- FileBothDirectoryInformation, FALSE, &info->mask, TRUE );
+ infoclass, FALSE, &info->mask, TRUE );
if (io.u.Status)
{
FindClose( info );
@@ -2052,8 +2061,10 @@ error:
BOOL WINAPI FindNextFileW( HANDLE handle, WIN32_FIND_DATAW *data )
{
FIND_FIRST_INFO *info;
- FILE_BOTH_DIR_INFORMATION *dir_info;
+ FILE_BOTH_DIR_INFORMATION *both_info;
BOOL ret = FALSE;
+ WCHAR *filename;
+ ULONG filenamelength;
TRACE("%p %p\n", handle, data);
@@ -2080,7 +2091,7 @@ BOOL WINAPI FindNextFileW( HANDLE handle, WIN32_FIND_DATAW *data )
if (info->data_size)
NtQueryDirectoryFile( info->handle, 0, NULL, NULL, &io, info->data, info->data_size,
- FileBothDirectoryInformation, FALSE, &info->mask, FALSE );
+ info->infoclass, FALSE, &info->mask, FALSE );
else
io.u.Status = STATUS_NO_MORE_FILES;
@@ -2100,41 +2111,64 @@ BOOL WINAPI FindNextFileW( HANDLE handle, WIN32_FIND_DATAW *data )
info->data_pos = 0;
}
- dir_info = (FILE_BOTH_DIR_INFORMATION *)(info->data + info->data_pos);
+ /* layout between full and both at the beginning is the same */
+ both_info = (FILE_BOTH_DIR_INFORMATION *)(info->data + info->data_pos);
+
+ /* The only differences are for FileName and ShortName */
+ if (info->infoclass == FileBothDirectoryInformation) {
+ filename = both_info->FileName;
+ filenamelength = both_info->FileNameLength;
+ FIXME("both fn length %d, fn %s\n", filenamelength, debugstr_w(filename));
+ } else if (info->infoclass == FileFullDirectoryInformation) {
+ FILE_FULL_DIR_INFORMATION *full_info = (FILE_FULL_DIR_INFORMATION *)(info->data + info->data_pos);
+
+ filename = full_info->FileName;
+ filenamelength = full_info->FileNameLength;
+ FIXME("full fn length %d, fn %s\n", filenamelength, debugstr_w(filename));
+ } else {
+ FIXME("infoclass %d, should not arrive here.\n", info->infoclass);
+ SetLastError( ERROR_INVALID_HANDLE );
+ return FALSE;
+ }
- if (dir_info->NextEntryOffset) info->data_pos += dir_info->NextEntryOffset;
+ if (both_info->NextEntryOffset) info->data_pos += both_info->NextEntryOffset;
else info->data_pos = info->data_len;
- /* don't return '.' and '..' in the root of the drive */
- if (info->is_root)
- {
- if (dir_info->FileNameLength == sizeof(WCHAR) && dir_info->FileName[0] == '.') continue;
- if (dir_info->FileNameLength == 2 * sizeof(WCHAR) &&
- dir_info->FileName[0] == '.' && dir_info->FileName[1] == '.') continue;
+ /* don't return '.' and '..' in the root of the drive */
+ if (info->is_root)
+ {
+ if (filenamelength == sizeof(WCHAR) && filename[0] == '.') continue;
+ if (filenamelength == 2 * sizeof(WCHAR) &&
+ filename[0] == '.' && filename[1] == '.') continue;
+ }
+
+ /* check for dir symlink */
+ if ((both_info->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
+ (both_info->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
+ strpbrkW( info->mask.Buffer, wildcardsW ))
+ {
+ if (!check_dir_symlink( info, filenamelength, filename )) continue;
+ }
+
+ data->dwFileAttributes = both_info->FileAttributes;
+ data->ftCreationTime = *(FILETIME *)&both_info->CreationTime;
+ data->ftLastAccessTime = *(FILETIME *)&both_info->LastAccessTime;
+ data->ftLastWriteTime = *(FILETIME *)&both_info->LastWriteTime;
+ data->nFileSizeHigh = both_info->EndOfFile.QuadPart >> 32;
+ data->nFileSizeLow = (DWORD)both_info->EndOfFile.QuadPart;
+ data->dwReserved0 = 0;
+ data->dwReserved1 = 0;
+
+ memcpy( data->cFileName, filename, filenamelength );
+ data->cFileName[filenamelength/sizeof(WCHAR)] = 0;
+
+ if (info->infoclass == FileBothDirectoryInformation) {
+ memcpy( data->cAlternateFileName, both_info->ShortName, both_info->ShortNameLength );
+ data->cAlternateFileName[both_info->ShortNameLength/sizeof(WCHAR)] = 0;
+ } else {
+ data->cAlternateFileName[0] = 0;
}
- /* check for dir symlink */
- if ((dir_info->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
- (dir_info->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
- strpbrkW( info->mask.Buffer, wildcardsW ))
- {
- if (!check_dir_symlink( info, dir_info )) continue;
- }
-
- data->dwFileAttributes = dir_info->FileAttributes;
- data->ftCreationTime = *(FILETIME *)&dir_info->CreationTime;
- data->ftLastAccessTime = *(FILETIME *)&dir_info->LastAccessTime;
- data->ftLastWriteTime = *(FILETIME *)&dir_info->LastWriteTime;
- data->nFileSizeHigh = dir_info->EndOfFile.QuadPart >> 32;
- data->nFileSizeLow = (DWORD)dir_info->EndOfFile.QuadPart;
- data->dwReserved0 = 0;
- data->dwReserved1 = 0;
-
- memcpy( data->cFileName, dir_info->FileName, dir_info->FileNameLength );
- data->cFileName[dir_info->FileNameLength/sizeof(WCHAR)] = 0;
- memcpy( data->cAlternateFileName, dir_info->ShortName, dir_info->ShortNameLength );
- data->cAlternateFileName[dir_info->ShortNameLength/sizeof(WCHAR)] = 0;
-
TRACE("returning %s (%s)\n",
debugstr_w(data->cFileName), debugstr_w(data->cAlternateFileName) );
diff --git a/dlls/kernel32/tests/file.c b/dlls/kernel32/tests/file.c
index 492a34f..f3529a0 100644
--- a/dlls/kernel32/tests/file.c
+++ b/dlls/kernel32/tests/file.c
@@ -2619,6 +2619,48 @@ static void test_FindFirstFileExA(FINDEX_SEARCH_OPS search_ops)
FindClose( handle );
+ /* Now do it without short names */
+
+ handle = pFindFirstFileExA("test-dir\\*", FindExInfoBasic, &search_results, search_ops, NULL, 0);
+ if (handle == INVALID_HANDLE_VALUE && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+ {
+ win_skip("FindFirstFileExA is not implemented\n");
+ goto cleanup;
+ }
+ ok(handle != INVALID_HANDLE_VALUE, "FindFirstFile failed (err=%u)\n", GetLastError());
+ ok(strcmp(search_results.cFileName, ".") == 0, "First entry should be '.', is %s\n", search_results.cFileName);
+
+#define CHECK_NAME(fn) (strcmp((fn), "file1") == 0 || strcmp((fn), "file2") == 0 || strcmp((fn), "dir1") == 0)
+
+ ok(FindNextFileA(handle, &search_results), "Fetching second file failed\n");
+ ok(strcmp(search_results.cFileName, "..") == 0, "Second entry should be '..' is %s\n", search_results.cFileName);
+
+ ok(FindNextFileA(handle, &search_results), "Fetching third file failed\n");
+ ok(CHECK_NAME(search_results.cFileName), "Invalid third entry - %s\n", search_results.cFileName);
+
+ SetLastError(0xdeadbeef);
+ ret = FindNextFileA(handle, &search_results);
+ if (!ret && (GetLastError() == ERROR_NO_MORE_FILES) && (search_ops == FindExSearchLimitToDirectories))
+ {
+ skip("File system supports directory filtering\n");
+ /* Results from the previous call are not cleared */
+ ok(strcmp(search_results.cFileName, "dir1") == 0, "Third entry should be 'dir1' is %s\n", search_results.cFileName);
+ FindClose( handle );
+ goto cleanup;
+ }
+
+ ok(ret, "Fetching fourth file failed\n");
+ ok(CHECK_NAME(search_results.cFileName), "Invalid fourth entry - %s\n", search_results.cFileName);
+
+ ok(FindNextFileA(handle, &search_results), "Fetching fifth file failed\n");
+ ok(CHECK_NAME(search_results.cFileName), "Invalid fifth entry - %s\n", search_results.cFileName);
+
+#undef CHECK_NAME
+
+ ok(FindNextFileA(handle, &search_results) == FALSE, "Fetching sixth file should fail\n");
+
+ FindClose( handle );
+
cleanup:
DeleteFileA("test-dir\\file1");
DeleteFileA("test-dir\\file2");
--
1.8.4.5
More information about the wine-patches
mailing list