#include #include #include #include #include #include #include #include static const CHAR testFile1A[] = "TestFile1A"; static BOOL create_fileA(const char* FilePath) { HANDLE hdl = CreateFileA(FilePath, GENERIC_ALL, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); if (hdl == INVALID_HANDLE_VALUE) return FALSE; (void)CloseHandle(hdl); return TRUE; } static BOOL create_fileW(const WCHAR* FilePath) { HANDLE hdl = CreateFileW(FilePath, GENERIC_ALL, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); if (hdl == INVALID_HANDLE_VALUE) return FALSE; (void)CloseHandle(hdl); return TRUE; } static BOOL create_layout_files(size_t level, const char* BasePath, wArrayList* files) { for (size_t x = 0; x < 10; x++) { CHAR FilePath[PATHCCH_MAX_CCH] = WINPR_C_ARRAY_INIT; strncpy(FilePath, BasePath, ARRAYSIZE(FilePath)); CHAR name[64] = WINPR_C_ARRAY_INIT; (void)_snprintf(name, ARRAYSIZE(name), "%zd-TestFile%zd", level, x); NativePathCchAppendA(FilePath, PATHCCH_MAX_CCH, name); if (create_fileA(FilePath)) ArrayList_Append(files, FilePath); } return TRUE; } static BOOL create_layout_directories(size_t level, size_t max_level, const char* BasePath, wArrayList* files) { if (level >= max_level) return TRUE; CHAR FilePath[PATHCCH_MAX_CCH] = WINPR_C_ARRAY_INIT; strncpy(FilePath, BasePath, ARRAYSIZE(FilePath)); PathCchConvertStyleA(FilePath, ARRAYSIZE(FilePath), PATH_STYLE_NATIVE); if (!winpr_PathMakePath(FilePath, nullptr)) return FALSE; ArrayList_Append(files, FilePath); if (!create_layout_files(level + 1, BasePath, files)) return FALSE; for (size_t x = 0; x < 10; x++) { CHAR CurFilePath[PATHCCH_MAX_CCH] = WINPR_C_ARRAY_INIT; strncpy(CurFilePath, FilePath, ARRAYSIZE(CurFilePath)); PathCchConvertStyleA(CurFilePath, ARRAYSIZE(CurFilePath), PATH_STYLE_NATIVE); CHAR name[64] = WINPR_C_ARRAY_INIT; (void)_snprintf(name, ARRAYSIZE(name), "%zd-TestPath%zd", level, x); NativePathCchAppendA(CurFilePath, PATHCCH_MAX_CCH, name); if (!create_layout_directories(level + 1, max_level, CurFilePath, files)) return FALSE; } return TRUE; } static BOOL create_layout(const char* BasePath, wArrayList* files) { CHAR BasePathNative[PATHCCH_MAX_CCH] = WINPR_C_ARRAY_INIT; memcpy(BasePathNative, BasePath, sizeof(BasePathNative)); PathCchConvertStyleA(BasePathNative, ARRAYSIZE(BasePathNative), PATH_STYLE_NATIVE); return create_layout_directories(0, 3, BasePathNative, files); } static void cleanup_layout(const char* BasePath) { winpr_RemoveDirectory_RecursiveA(BasePath); } static BOOL find_first_file_success(const char* FilePath) { BOOL rc = FALSE; WIN32_FIND_DATAA FindData = WINPR_C_ARRAY_INIT; HANDLE hFind = FindFirstFileA(FilePath, &FindData); if (hFind == INVALID_HANDLE_VALUE) { printf("FindFirstFile failure: %s (INVALID_HANDLE_VALUE -1)\n", FilePath); goto fail; } printf("FindFirstFile: %s\n", FindData.cFileName); if (strcmp(FindData.cFileName, testFile1A) != 0) { printf("FindFirstFile failure: Expected: %s, Actual: %s\n", testFile1A, FindData.cFileName); goto fail; } rc = TRUE; fail: if (hFind != INVALID_HANDLE_VALUE) FindClose(hFind); return rc; } static BOOL list_directory_dot(const char* BasePath, wArrayList* files) { BOOL rc = FALSE; CHAR BasePathDot[PATHCCH_MAX_CCH] = WINPR_C_ARRAY_INIT; memcpy(BasePathDot, BasePath, ARRAYSIZE(BasePathDot)); PathCchConvertStyleA(BasePathDot, ARRAYSIZE(BasePathDot), PATH_STYLE_NATIVE); NativePathCchAppendA(BasePathDot, PATHCCH_MAX_CCH, "."); WIN32_FIND_DATAA FindData = WINPR_C_ARRAY_INIT; HANDLE hFind = FindFirstFileA(BasePathDot, &FindData); if (hFind == INVALID_HANDLE_VALUE) return FALSE; size_t count = 0; do { count++; if (strcmp(FindData.cFileName, ".") != 0) goto fail; } while (FindNextFile(hFind, &FindData)); rc = TRUE; fail: FindClose(hFind); if (count != 1) return FALSE; return rc; } static BOOL list_directory_star(const char* BasePath, wArrayList* files) { CHAR BasePathDot[PATHCCH_MAX_CCH] = WINPR_C_ARRAY_INIT; memcpy(BasePathDot, BasePath, ARRAYSIZE(BasePathDot)); PathCchConvertStyleA(BasePathDot, ARRAYSIZE(BasePathDot), PATH_STYLE_NATIVE); NativePathCchAppendA(BasePathDot, PATHCCH_MAX_CCH, "*"); WIN32_FIND_DATAA FindData = WINPR_C_ARRAY_INIT; HANDLE hFind = FindFirstFileA(BasePathDot, &FindData); if (hFind == INVALID_HANDLE_VALUE) return FALSE; size_t count = 0; size_t dotcount = 0; size_t dotdotcount = 0; do { if (strcmp(FindData.cFileName, ".") == 0) dotcount++; else if (strcmp(FindData.cFileName, "..") == 0) dotdotcount++; else count++; } while (FindNextFile(hFind, &FindData)); FindClose(hFind); const char sep = PathGetSeparatorA(PATH_STYLE_NATIVE); size_t fcount = 0; const size_t baselen = strlen(BasePath); const size_t total = ArrayList_Count(files); for (size_t x = 0; x < total; x++) { const char* path = ArrayList_GetItem(files, x); const size_t pathlen = strlen(path); if (pathlen < baselen) continue; const char* skip = &path[baselen]; if (*skip == sep) skip++; const char* end = strrchr(skip, sep); if (end) continue; fcount++; } return (fcount == count); } static BOOL find_first_file_fail(const char* FilePath) { WIN32_FIND_DATAA FindData = WINPR_C_ARRAY_INIT; HANDLE hFind = FindFirstFileA(FilePath, &FindData); if (hFind == INVALID_HANDLE_VALUE) return TRUE; FindClose(hFind); return FALSE; } static int TestFileFindFirstFileA(const char* str) { int rc = -1; printf("[%s] basepath: '%s'\n", __func__, str); if (!str) return -1; CHAR BasePath[PATHCCH_MAX_CCH] = WINPR_C_ARRAY_INIT; strncpy(BasePath, str, ARRAYSIZE(BasePath)); const size_t length = strnlen(BasePath, PATHCCH_MAX_CCH - 1); CHAR FilePath[PATHCCH_MAX_CCH] = WINPR_C_ARRAY_INIT; CopyMemory(FilePath, BasePath, length * sizeof(CHAR)); PathCchConvertStyleA(BasePath, length, PATH_STYLE_WINDOWS); wArrayList* files = ArrayList_New(FALSE); if (!files) return -3; wObject* obj = ArrayList_Object(files); obj->fnObjectFree = winpr_ObjectStringFree; obj->fnObjectNew = winpr_ObjectStringClone; if (!create_layout(BasePath, files)) goto fail; NativePathCchAppendA(FilePath, PATHCCH_MAX_CCH, testFile1A); printf("Finding file: %s\n", FilePath); if (!find_first_file_fail(FilePath)) goto fail; if (!create_fileA(FilePath)) goto fail; if (!find_first_file_success(FilePath)) goto fail; CHAR BasePathInvalid[PATHCCH_MAX_CCH] = WINPR_C_ARRAY_INIT; memcpy(BasePathInvalid, BasePath, ARRAYSIZE(BasePathInvalid)); PathCchAddBackslashA(BasePathInvalid, PATHCCH_MAX_CCH); if (!find_first_file_fail(BasePathInvalid)) goto fail; if (!list_directory_dot(BasePath, files)) goto fail; if (!list_directory_star(BasePath, files)) goto fail; rc = 0; fail: winpr_DeleteFile(FilePath); cleanup_layout(BasePath); ArrayList_Free(files); return rc; } WINPR_ATTR_FORMAT_ARG(1, 0) static int printf1W(const char* WINPR_FORMAT_ARG fmt, const WCHAR* arg1) { char* var1 = ConvertWCharToUtf8Alloc(arg1, nullptr); const int rc = printf(fmt, var1); free(var1); return rc; } WINPR_ATTR_FORMAT_ARG(1, 0) static int printf2W(const char* WINPR_FORMAT_ARG fmt, const WCHAR* arg1, const WCHAR* arg2) { char* var1 = ConvertWCharToUtf8Alloc(arg1, nullptr); char* var2 = ConvertWCharToUtf8Alloc(arg2, nullptr); const int rc = printf(fmt, var1, var2); free(var1); free(var2); return rc; } static int TestFileFindFirstFileW(const char* str) { WCHAR buffer[32] = WINPR_C_ARRAY_INIT; const WCHAR* testFile1W = InitializeConstWCharFromUtf8("TestFile1W", buffer, ARRAYSIZE(buffer)); int rc = -1; if (!str) return -1; WCHAR BasePath[PATHCCH_MAX_CCH] = WINPR_C_ARRAY_INIT; printf("[%s] basepath: '%s'\n", __func__, str); (void)ConvertUtf8ToWChar(str, BasePath, ARRAYSIZE(BasePath)); const size_t length = _wcsnlen(BasePath, PATHCCH_MAX_CCH - 1); WCHAR FilePath[PATHCCH_MAX_CCH] = WINPR_C_ARRAY_INIT; CopyMemory(FilePath, BasePath, length * sizeof(WCHAR)); PathCchConvertStyleW(BasePath, length, PATH_STYLE_WINDOWS); NativePathCchAppendW(FilePath, PATHCCH_MAX_CCH, testFile1W); HANDLE hFind = INVALID_HANDLE_VALUE; if (!create_fileW(FilePath)) goto fail; printf1W("Finding file: %s\n", FilePath); WIN32_FIND_DATAW FindData = WINPR_C_ARRAY_INIT; hFind = FindFirstFileW(FilePath, &FindData); if (hFind == INVALID_HANDLE_VALUE) { printf1W("FindFirstFile failure: %s (INVALID_HANDLE_VALUE -1)\n", FilePath); goto fail; } printf1W("FindFirstFile: %s\n", FindData.cFileName); if (_wcscmp(FindData.cFileName, testFile1W) != 0) { printf2W("FindFirstFile failure: Expected: %s, Actual: %s\n", testFile1W, FindData.cFileName); goto fail; } rc = 0; fail: DeleteFileW(FilePath); FindClose(hFind); return rc; } int TestFileFindFirstFile(int argc, char* argv[]) { char* str = GetKnownSubPath(KNOWN_PATH_TEMP, "TestFileFindFirstFile"); if (!str) return -23; cleanup_layout(str); int rc1 = -1; int rc2 = -1; if (winpr_PathMakePath(str, nullptr)) { rc1 = TestFileFindFirstFileA(str); rc2 = TestFileFindFirstFileW(str); winpr_RemoveDirectory(str); } free(str); return rc1 + rc2; }