diff --git a/src/system.c b/src/system.c index a98a999..be02667 100644 --- a/src/system.c +++ b/src/system.c @@ -31,6 +31,7 @@ typedef enum { DESC_SOCKET, DESC_LISTEN_SOCKET, DESC_CONNECTION_SOCKET, + DESC_DIRECTORY, } DescriptorType; typedef enum { @@ -84,6 +85,14 @@ typedef struct { NATIVE_HANDLE real_fd; + // ------ Directory ------------- + +#ifdef _WIN32 + HANDLE real_d; +#else + DIR *real_d; +#endif + // ------ Socket ---------------- // Events reported by the last "poll" call @@ -1236,6 +1245,14 @@ static void close_desc(Descriptor *desc) } // TODO break; + + case DESC_DIRECTORY: +#ifdef _WIN32 + FindClose(desc->real_d); +#else + closedir(desc->real_d); +#endif + break; } desc->type = DESC_EMPTY; desc->generation++; @@ -1503,6 +1520,71 @@ int mock_ioctlsocket(SOCKET fd, long cmd, u_long *argp) return -1; } +HANDLE mock_FindFirstFileA(char *lpFileName, WIN32_FIND_DATAA *lpFindFileData) +{ + HANDLE handle = FindFirstFileA(lpFileName, lpFindFileData); + if (handle == INVALID_HANDLE_VALUE) + return INVALID_HANDLE_VALUE; + + if (current_process->num_desc == MAX_DESCRIPTORS) { + FindClose(handle); + SetLastError(ERROR_TOO_MANY_OPEN_FILES); + return INVALID_HANDLE_VALUE; + } + + int idx = 0; + while (current_process->desc[idx].type != DESC_EMPTY) { + idx++; + assert(idx < MAX_DESCRIPTORS); + } + + Descriptor *desc = ¤t_process->desc[idx]; + desc->type = DESC_DIRECTORY; + desc->real_d = handle; + + current_process->num_desc++; + CHECK_NON_EMPTY_DESC_INVARIANT; + return (HANDLE) idx; +} + +BOOL mock_FindNextFileA(HANDLE hFindFile, WIN32_FIND_DATAA *lpFindFileData) +{ + if (hFindFile == INVALID_HANDLE_VALUE || (int)hFindFile < 0 || (int)hFindFile >= MAX_DESCRIPTORS) { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + int idx = (int) hFindFile; + + Descriptor *desc = ¤t_process->desc[idx]; + if (desc->type != DESC_DIRECTORY) { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + // Forward to real FindNextFileA, last error is set by the real call + return FindNextFileA(desc->real_d, lpFindFileData); +} + +BOOL mock_FindClose(HANDLE hFindFile) +{ + if (hFindFile == INVALID_HANDLE_VALUE || (int)hFindFile < 0 || (int)hFindFile >= MAX_DESCRIPTORS) { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + int idx = (int) hFindFile; + + Descriptor *desc = ¤t_process->desc[idx]; + if (desc->type != DESC_DIRECTORY) { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + close_desc(desc); + current_process->num_desc--; + CHECK_NON_EMPTY_DESC_INVARIANT; + return TRUE; +} + #else int mock_clock_gettime(clockid_t clockid, struct timespec *tp) @@ -1736,6 +1818,81 @@ int mock_fcntl(int fd, int cmd, ...) return -1; } +DIR *mock_opendir(char *name) +{ + DIR *dir = opendir(name); + if (dir == NULL) + return NULL; + + if (current_process->num_desc == MAX_DESCRIPTORS) { + closedir(dir); + errno = EMFILE; // Too many open files + return NULL; + } + + int idx = 0; + while (current_process->desc[idx].type != DESC_EMPTY) { + idx++; + assert(idx < MAX_DESCRIPTORS); + } + + Descriptor *desc = ¤t_process->desc[idx]; + desc->type = DESC_DIRECTORY; + desc->real_d = dir; + + current_process->num_desc++; + CHECK_NON_EMPTY_DESC_INVARIANT; + return (DIR *)(intptr_t) idx; +} + +struct dirent *mock_readdir(DIR *dirp) +{ + if (dirp == NULL) { + errno = EBADF; // Bad file descriptor + return NULL; + } + int idx = (int)(intptr_t) dirp; + + if (idx < 0 || idx >= MAX_DESCRIPTORS) { + errno = EBADF; + return NULL; + } + + Descriptor *desc = ¤t_process->desc[idx]; + if (desc->type != DESC_DIRECTORY) { + errno = EBADF; + return NULL; + } + + // Forward to real readdir, errno is set by the real call + return readdir(desc->real_d); +} + +int mock_closedir(DIR *dirp) +{ + if (dirp == NULL) { + errno = EBADF; // Bad file descriptor + return -1; + } + int idx = (int)(intptr_t) dirp; + + if (idx < 0 || idx >= MAX_DESCRIPTORS) { + errno = EBADF; + return -1; + } + + Descriptor *desc = ¤t_process->desc[idx]; + if (desc->type != DESC_DIRECTORY) { + errno = EBADF; + return -1; + } + + close_desc(desc); + current_process->num_desc--; + CHECK_NON_EMPTY_DESC_INVARIANT; + return 0; +} + #endif // !_WIN32 #endif // BUILD_TEST diff --git a/src/system.h b/src/system.h index aeea168..31ba995 100644 --- a/src/system.h +++ b/src/system.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -69,6 +70,9 @@ BOOL mock_QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount); BOOL mock_QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency); char* mock__fullpath(char *path, char *dst, int cap); int mock__mkdir(char *path); +HANDLE mock_FindFirstFileA(char *lpFileName, WIN32_FIND_DATAA *lpFindFileData); +BOOL mock_FindNextFileA(HANDLE hFindFile, WIN32_FIND_DATAA *lpFindFileData); +BOOL mock_FindClose(HANDLE hFindFile); #else int mock_clock_gettime(clockid_t clockid, struct timespec *tp); int mock_open(char *path, int flags, int mode); @@ -82,6 +86,9 @@ int mock_mkstemp(char *path); char* mock_realpath(char *path, char *dst); int mock_mkdir(char *path, mode_t mode); int mock_fcntl(int fd, int cmd, ...); +DIR* mock_opendir(char *name); +struct dirent* mock_readdir(DIR *dirp); +int mock_closedir(DIR *dirp); #endif // Common @@ -114,6 +121,9 @@ int mock_fcntl(int fd, int cmd, ...); #define sys__fullpath mock__fullpath #define sys_QueryPerformanceCounter mock_QueryPerformanceCounter #define sys_QueryPerformanceFrequency mock_QueryPerformanceFrequency +#define sys_FindFirstFileA mock_FindFirstFileA +#define sys_FindNextFileA mock_FindNextFileA +#define sys_FindClose mock_FindClose // Linux #define sys_mkdir mock_mkdir @@ -129,6 +139,9 @@ int mock_fcntl(int fd, int cmd, ...); #define sys_clock_gettime mock_clock_gettime #define sys_fcntl mock_fcntl #define sys_getrandom mock_getrandom +#define sys_opendir mock_opendir +#define sys_readdir mock_readdir +#define sys_closedir mock_closedir #else @@ -162,6 +175,9 @@ int mock_fcntl(int fd, int cmd, ...); #define sys__fullpath _fullpath #define sys_QueryPerformanceCounter QueryPerformanceCounter #define sys_QueryPerformanceFrequency QueryPerformanceFrequency +#define sys_FindFirstFileA FindFirstFileA +#define sys_FindNextFileA FindNextFileA +#define sys_FindClose FindClose // Linux #define sys_mkdir mkdir @@ -176,6 +192,9 @@ int mock_fcntl(int fd, int cmd, ...); #define sys_realpath realpath #define sys_clock_gettime clock_gettime #define sys_fcntl fcntl +#define sys_opendir opendir +#define sys_readdir readdir +#define sys_closedir closedir #endif #endif // SYSTEM_INCLUDED