--- dlls/kernel32/file.c +++ dlls/kernel32/file.c @@ -1553,6 +1553,7 @@ HANDLE WINAPI FindFirstFileExW( LPCWSTR OBJECT_ATTRIBUTES attr; IO_STATUS_BLOCK io; NTSTATUS status; + DWORD device = 0; TRACE("%s %d %p %d %p %x\n", debugstr_w(filename), level, data, search_op, filter, flags); @@ -1574,27 +1575,56 @@ HANDLE WINAPI FindFirstFileExW( LPCWSTR return INVALID_HANDLE_VALUE; } - if (!mask || !*mask) - { - SetLastError( ERROR_FILE_NOT_FOUND ); - goto error; - } - if (!(info = HeapAlloc( GetProcessHeap(), 0, sizeof(*info)))) { SetLastError( ERROR_NOT_ENOUGH_MEMORY ); goto error; } - if (!RtlCreateUnicodeString( &info->mask, mask )) + if (!mask && (device = RtlIsDosDeviceName_U( filename ))) { - SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + static const WCHAR dotW[] = {'.',0}; + WCHAR *dir = NULL; + + /* we still need to check that the directory can be opened */ + + if (HIWORD(device)) + { + if (!(dir = HeapAlloc( GetProcessHeap(), 0, HIWORD(device) + sizeof(WCHAR) ))) + { + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + goto error; + } + memcpy( dir, filename, HIWORD(device) ); + dir[HIWORD(device)/sizeof(WCHAR)] = 0; + } + RtlFreeUnicodeString( &nt_name ); + if (!RtlDosPathNameToNtPathName_U( dir ? dir : dotW, &nt_name, &mask, NULL )) + { + HeapFree( GetProcessHeap(), 0, dir ); + SetLastError( ERROR_PATH_NOT_FOUND ); + goto error; + } + HeapFree( GetProcessHeap(), 0, dir ); + RtlInitUnicodeString( &info->mask, NULL ); + } + else if (!mask || !*mask) + { + SetLastError( ERROR_FILE_NOT_FOUND ); goto error; } + else + { + if (!RtlCreateUnicodeString( &info->mask, mask )) + { + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + goto error; + } - /* truncate dir name before mask */ - *mask = 0; - nt_name.Length = (mask - nt_name.Buffer) * sizeof(WCHAR); + /* truncate dir name before mask */ + *mask = 0; + nt_name.Length = (mask - nt_name.Buffer) * sizeof(WCHAR); + } /* check if path is the root of the drive */ info->is_root = FALSE; @@ -1620,7 +1650,10 @@ HANDLE WINAPI FindFirstFileExW( LPCWSTR if (status != STATUS_SUCCESS) { RtlFreeUnicodeString( &info->mask ); - SetLastError( RtlNtStatusToDosError(status) ); + if (status == STATUS_OBJECT_NAME_NOT_FOUND) + SetLastError( ERROR_PATH_NOT_FOUND ); + else + SetLastError( RtlNtStatusToDosError(status) ); goto error; } @@ -1631,14 +1664,24 @@ HANDLE WINAPI FindFirstFileExW( LPCWSTR info->data_len = 0; info->search_op = search_op; - if (!FindNextFileW( (HANDLE)info, data )) + if (device) + { + WIN32_FIND_DATAW *wfd = data; + + memset( wfd, 0, sizeof(*wfd) ); + memcpy( wfd->cFileName, filename + HIWORD(device)/sizeof(WCHAR), LOWORD(device) ); + wfd->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE; + CloseHandle( info->handle ); + info->handle = 0; + } + else if (!FindNextFileW( (HANDLE)info, data )) { TRACE( "%s not found\n", debugstr_w(filename) ); FindClose( (HANDLE)info ); SetLastError( ERROR_FILE_NOT_FOUND ); return INVALID_HANDLE_VALUE; } - if (!strpbrkW( info->mask.Buffer, wildcardsW )) + else if (!strpbrkW( info->mask.Buffer, wildcardsW )) { /* we can't find two files with the same name */ CloseHandle( info->handle ); --- dlls/kernel32/tests/file.c 2006-10-27 17:20:13.000000000 +0200 +++ dlls/kernel32/tests/file.c.patched 2006-10-31 17:25:52.000000000 +0100 @@ -1186,7 +1186,7 @@ static void test_FindFirstFileA(void) { HANDLE handle; - WIN32_FIND_DATAA search_results; + WIN32_FIND_DATAA data; int err; char buffer[5] = "C:\\"; char buffer2[100]; @@ -1195,7 +1195,7 @@ buffer[0] = get_windows_drive(); SetLastError( 0xdeadbeaf ); - handle = FindFirstFileA(buffer, &search_results); + handle = FindFirstFileA(buffer, &data); err = GetLastError(); ok ( handle == INVALID_HANDLE_VALUE, "FindFirstFile on root directory should fail\n" ); ok ( err == ERROR_FILE_NOT_FOUND, "Bad Error number %d\n", err ); @@ -1203,7 +1203,7 @@ /* try FindFirstFileA on "C:\*" */ strcpy(buffer2, buffer); strcat(buffer2, "*"); - handle = FindFirstFileA(buffer2, &search_results); + handle = FindFirstFileA(buffer2, &data); ok ( handle != INVALID_HANDLE_VALUE, "FindFirstFile on %s should succeed\n", buffer2 ); ok ( FindClose(handle) == TRUE, "Failed to close handle %s\n", buffer2 ); @@ -1211,7 +1211,7 @@ SetLastError( 0xdeadbeaf ); strcpy(buffer2, buffer); strcat(buffer2, "foo\\"); - handle = FindFirstFileA(buffer2, &search_results); + handle = FindFirstFileA(buffer2, &data); err = GetLastError(); ok ( handle == INVALID_HANDLE_VALUE, "FindFirstFile on %s should Fail\n", buffer2 ); todo_wine { @@ -1222,33 +1222,94 @@ SetLastError( 0xdeadbeaf ); strcpy(buffer2, buffer); strcat(buffer2, "foo\\bar.txt"); - handle = FindFirstFileA(buffer2, &search_results); + handle = FindFirstFileA(buffer2, &data); err = GetLastError(); ok ( handle == INVALID_HANDLE_VALUE, "FindFirstFile on %s should Fail\n", buffer2 ); - todo_wine { - ok ( err == ERROR_PATH_NOT_FOUND, "Bad Error number %d\n", err ); - } + ok ( err == ERROR_PATH_NOT_FOUND, "Bad Error number %d\n", err ); /* try FindFirstFileA on "C:\foo\*.*" */ SetLastError( 0xdeadbeaf ); strcpy(buffer2, buffer); strcat(buffer2, "foo\\*.*"); - handle = FindFirstFileA(buffer2, &search_results); + handle = FindFirstFileA(buffer2, &data); err = GetLastError(); ok ( handle == INVALID_HANDLE_VALUE, "FindFirstFile on %s should Fail\n", buffer2 ); - todo_wine { - ok ( err == ERROR_PATH_NOT_FOUND, "Bad Error number %d\n", err ); - } + ok ( err == ERROR_PATH_NOT_FOUND, "Bad Error number %d\n", err ); /* try FindFirstFileA on "foo\bar.txt" */ SetLastError( 0xdeadbeaf ); strcpy(buffer2, "foo\\bar.txt"); - handle = FindFirstFileA(buffer2, &search_results); + handle = FindFirstFileA(buffer2, &data); err = GetLastError(); ok ( handle == INVALID_HANDLE_VALUE, "FindFirstFile on %s should Fail\n", buffer2 ); - todo_wine { - ok ( err == ERROR_PATH_NOT_FOUND, "Bad Error number %d\n", err ); - } + ok ( err == ERROR_PATH_NOT_FOUND, "Bad Error number %d\n", err ); + + /* try FindFirstFileA on "c:\nul" */ + SetLastError( 0xdeadbeaf ); + strcpy(buffer2, buffer); + strcat(buffer2, "nul"); + handle = FindFirstFileA(buffer2, &data); + err = GetLastError(); + ok( handle != INVALID_HANDLE_VALUE, "FindFirstFile on %s failed\n", buffer2 ); + ok( 0 == lstrcmpiA(data.cFileName, "nul"), "wrong name %s\n", data.cFileName ); + ok( 0 == data.nFileSizeHigh, "wrong size %d\n", data.nFileSizeHigh ); + ok( 0 == data.nFileSizeLow, "wrong size %d\n", data.nFileSizeLow ); + ok( FILE_ATTRIBUTE_ARCHIVE == data.dwFileAttributes, "wrong attributes %x\n", data.dwFileAttributes ); + SetLastError( 0xdeadbeaf ); + ok( !FindNextFileA( handle, &data ), "FindNextFileA succeeded\n" ); + ok( GetLastError() == ERROR_NO_MORE_FILES, "bad error %d\n", GetLastError() ); + ok( FindClose( handle ), "failed to close handle\n" ); + + /* try FindFirstFileA on "lpt1" */ + SetLastError( 0xdeadbeaf ); + strcpy(buffer2, "lpt1"); + handle = FindFirstFileA(buffer2, &data); + err = GetLastError(); + ok( handle != INVALID_HANDLE_VALUE, "FindFirstFile on %s failed\n", buffer2 ); + ok( 0 == lstrcmpiA(data.cFileName, "lpt1"), "wrong name %s\n", data.cFileName ); + ok( 0 == data.nFileSizeHigh, "wrong size %d\n", data.nFileSizeHigh ); + ok( 0 == data.nFileSizeLow, "wrong size %d\n", data.nFileSizeLow ); + ok( FILE_ATTRIBUTE_ARCHIVE == data.dwFileAttributes, "wrong attributes %x\n", data.dwFileAttributes ); + SetLastError( 0xdeadbeaf ); + ok( !FindNextFileA( handle, &data ), "FindNextFileA succeeded\n" ); + ok( GetLastError() == ERROR_NO_MORE_FILES, "bad error %d\n", GetLastError() ); + ok( FindClose( handle ), "failed to close handle\n" ); + + /* try FindFirstFileA on "c:\nul\*" */ + SetLastError( 0xdeadbeaf ); + strcpy(buffer2, buffer); + strcat(buffer2, "nul\\*"); + handle = FindFirstFileA(buffer2, &data); + err = GetLastError(); + ok ( handle == INVALID_HANDLE_VALUE, "FindFirstFile on %s should Fail\n", buffer2 ); + ok ( err == ERROR_PATH_NOT_FOUND, "Bad Error number %d\n", err ); + + /* try FindFirstFileA on "c:\nul*" */ + SetLastError( 0xdeadbeaf ); + strcpy(buffer2, buffer); + strcat(buffer2, "nul*"); + handle = FindFirstFileA(buffer2, &data); + err = GetLastError(); + ok ( handle == INVALID_HANDLE_VALUE, "FindFirstFile on %s should Fail\n", buffer2 ); + ok ( err == ERROR_FILE_NOT_FOUND, "Bad Error number %d\n", err ); + + /* try FindFirstFileA on "c:\foo\bar\nul" */ + SetLastError( 0xdeadbeaf ); + strcpy(buffer2, buffer); + strcat(buffer2, "foo\\bar\\nul"); + handle = FindFirstFileA(buffer2, &data); + err = GetLastError(); + ok ( handle == INVALID_HANDLE_VALUE, "FindFirstFile on %s should Fail\n", buffer2 ); + ok ( err == ERROR_PATH_NOT_FOUND, "Bad Error number %d\n", err ); + + /* try FindFirstFileA on "c:\foo\nul\bar" */ + SetLastError( 0xdeadbeaf ); + strcpy(buffer2, buffer); + strcat(buffer2, "foo\\nul\\bar"); + handle = FindFirstFileA(buffer2, &data); + err = GetLastError(); + ok ( handle == INVALID_HANDLE_VALUE, "FindFirstFile on %s should Fail\n", buffer2 ); + ok ( err == ERROR_PATH_NOT_FOUND, "Bad Error number %d\n", err ); } static void test_FindNextFileA(void)