361 lines
9.2 KiB
C
361 lines
9.2 KiB
C
|
|
#include <stdio.h>
|
|
#include <winpr/crt.h>
|
|
#include <winpr/handle.h>
|
|
#include <winpr/file.h>
|
|
#include <winpr/path.h>
|
|
#include <winpr/tchar.h>
|
|
#include <winpr/collections.h>
|
|
#include <winpr/windows.h>
|
|
|
|
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;
|
|
}
|