VOID SCALL LogFileFormatV(const CHAR *format, va_list argList) { DWORD errorCode; LOG_ENTRY *entry; size_t remaining; // Preserve system error code errorCode = GetLastError(); ASSERT(format != NULL); // Retrieve a spare entry structure (also checks log status) entry = GetSpareEntry(); if (entry != NULL) { GetLocalTime(&entry->time); StringCchVPrintfExA(entry->message, ELEMENT_COUNT(entry->message), NULL, &remaining, 0, format, argList); entry->length = ELEMENT_COUNT(entry->message) - remaining; // Insert log entry into the write queue QueueInsert(entry); } // Restore system error code SetLastError(errorCode); }
VOID SCALL LogFileTraceV(const CHAR *file, const CHAR *func, INT line, const CHAR *format, va_list argList) { #if 0 CHAR location[MAX_PATH]; #endif CHAR *messageEnd; DWORD errorCode; DWORD processId; DWORD threadId; LOG_ENTRY *entry; size_t remaining; // Preserve system error code errorCode = GetLastError(); ASSERT(file != NULL); ASSERT(func != NULL); ASSERT(format != NULL); processId = GetCurrentProcessId(); threadId = GetCurrentThreadId(); // Retrieve a spare entry structure (also checks log status) entry = GetSpareEntry(); if (entry != NULL) { // // Available trace information: // // file - Source file // func - Function name in the source file // line - Line number in the source file // processId - Current process ID // threadId - Current thread ID // GetLocalTime(&entry->time); #if 0 StringCchPrintfA(location, ELEMENT_COUNT(location), "%s:%d", LogFileName(file), line); StringCchPrintfExA(entry->message, ELEMENT_COUNT(entry->message), &messageEnd, &remaining, 0, "%-20s - %-20s - ", location, func); #else StringCchPrintfExA(entry->message, ELEMENT_COUNT(entry->message), &messageEnd, &remaining, 0, "%s - ", func); #endif StringCchVPrintfExA(messageEnd, remaining, NULL, &remaining, 0, format, argList); entry->length = ELEMENT_COUNT(entry->message) - remaining; // Insert log entry into the write queue QueueInsert(entry); } // Restore system error code SetLastError(errorCode); }
void test_different_lists(void) { TEST_IGNORE(); int list_to_compare[] = { 1, 2, 3 }; int base_list[] = { 2, 3, 4 }; TEST_ASSERT_EQUAL(UNEQUAL, check_lists(list_to_compare, base_list, ELEMENT_COUNT(list_to_compare), ELEMENT_COUNT(base_list))); }
void test_order_matters_to_a_list(void) { TEST_IGNORE(); int list_to_compare[] = { 1, 2, 3 }; int base_list[] = { 3, 2, 1 }; TEST_ASSERT_EQUAL(UNEQUAL, check_lists(list_to_compare, base_list, ELEMENT_COUNT(list_to_compare), ELEMENT_COUNT(base_list))); }
void test_false_start(void) { TEST_IGNORE(); int list_to_compare[] = { 1, 2, 5 }; int base_list[] = { 0, 1, 2, 3, 1, 2, 5, 6 }; TEST_ASSERT_EQUAL(SUBLIST, check_lists(list_to_compare, base_list, ELEMENT_COUNT(list_to_compare), ELEMENT_COUNT(base_list))); }
void test_second_list_missing_element_from_first_list(void) { TEST_IGNORE(); int list_to_compare[] = { 1, 2, 3 }; int base_list[] = { 1, 3 }; TEST_ASSERT_EQUAL(UNEQUAL, check_lists(list_to_compare, base_list, ELEMENT_COUNT(list_to_compare), ELEMENT_COUNT(base_list))); }
void test_at_end_of_superlist(void) { TEST_IGNORE(); int list_to_compare[] = { 0, 1, 2, 3, 4, 5 }; int base_list[] = { 3, 4, 5 }; TEST_ASSERT_EQUAL(SUPERLIST, check_lists(list_to_compare, base_list, ELEMENT_COUNT(list_to_compare), ELEMENT_COUNT(base_list))); }
void test_consecutive(void) { TEST_IGNORE(); int list_to_compare[] = { 1, 1, 2 }; int base_list[] = { 0, 1, 1, 1, 2, 1, 2 }; TEST_ASSERT_EQUAL(SUBLIST, check_lists(list_to_compare, base_list, ELEMENT_COUNT(list_to_compare), ELEMENT_COUNT(base_list))); }
void test_sublist_at_middle(void) { TEST_IGNORE(); int list_to_compare[] = { 2, 3, 4 }; int base_list[] = { 0, 1, 2, 3, 4, 5 }; TEST_ASSERT_EQUAL(SUBLIST, check_lists(list_to_compare, base_list, ELEMENT_COUNT(list_to_compare), ELEMENT_COUNT(base_list))); }
void test_list_equals_itself(void) { TEST_IGNORE(); int list_to_compare[] = { 1, 2, 3 }; int base_list[] = { 1, 2, 3 }; TEST_ASSERT_EQUAL(EQUAL, check_lists(list_to_compare, base_list, ELEMENT_COUNT(list_to_compare), ELEMENT_COUNT(base_list))); }
void test_same_digits_but_different_numbers(void) { TEST_IGNORE(); int list_to_compare[] = { 1, 0, 1 }; int base_list[] = { 10, 1 }; TEST_ASSERT_EQUAL(UNEQUAL, check_lists(list_to_compare, base_list, ELEMENT_COUNT(list_to_compare), ELEMENT_COUNT(base_list))); }
static VOID CCALL QueueWrite(VOID *context) { CHAR buffer[128]; DWORD written; HANDLE file; LOG_ENTRY *entry; size_t remaining; UNREFERENCED_PARAMETER(context); // Log system must be inactive or shutting down (flush) if (logStatus != LOG_STATUS_ACTIVE && logStatus != LOG_STATUS_SHUTDOWN) { return; } file = FileOpen(logPath, GENERIC_WRITE, FILE_SHARE_READ, 10); if (file == INVALID_HANDLE_VALUE) { return; } // Process all queued log entries for (;;) { entry = GetQueueEntry(); if (entry == NULL) { break; } // Format the time stamp StringCchPrintfExA(buffer, ELEMENT_COUNT(buffer), NULL, &remaining, 0, "%02d-%02d-%04d %02d:%02d:%02d ", entry->time.wMonth, entry->time.wDay, entry->time.wYear, entry->time.wHour, entry->time.wMinute, entry->time.wSecond); // Seek to the end of the log file SetFilePointer(file, 0, 0, FILE_END); if (!WriteFile(file, buffer, ELEMENT_COUNT(buffer) - remaining, &written, NULL)) { TRACE("Unable to write log file (error %lu).", GetLastError()); } if (!WriteFile(file, entry->message, entry->length, &written, NULL)) { TRACE("Unable to write log file (error %lu).", GetLastError()); } MemFree(entry); } CloseHandle(file); }
/*++ TraceFormat Sends the message to a debugger. Arguments: funct - Pointer to a null-terminated string that specifies the function. format - Pointer to a null-terminated printf-style format string. ... - Arguments to insert into "format". Return Values: None. --*/ VOID CCALL TraceFormat(const char *funct, const char *format, ...) { char *end; char output[1024]; DWORD error; size_t remaining; va_list argList; ASSERT(funct != NULL); ASSERT(format != NULL); // Preserve system error code error = GetLastError(); StringCchPrintfExA(output, ELEMENT_COUNT(output), &end, &remaining, 0, "| %4d | %17s | ", GetCurrentThreadId(), funct); va_start(argList, format); StringCchVPrintfA(end, remaining, format, argList); va_end(argList); OutputDebugStringA(output); // Restore system error code SetLastError(error); }
DWORD FileGroupDelete(INT32 groupId) { CHAR *path; CHAR buffer[12]; DWORD result; ASSERT(groupId != -1); TRACE("groupId=%d", groupId); // Retrieve group file location StringCchPrintfA(buffer, ELEMENT_COUNT(buffer), "%i", groupId); path = Io_ConfigGetPath("Locations", "Group_Files", buffer, NULL); if (path == NULL) { TRACE("Unable to retrieve file location."); return ERROR_NOT_ENOUGH_MEMORY; } // Delete group file and free resources if (DeleteFileA(path)) { result = ERROR_SUCCESS; } else { result = GetLastError(); TRACE("Unable to delete file \"%s\" (error %lu).", path, result); } Io_Free(path); return result; }
/*++ ConnectionClose Closes the server connection. Arguments: context - Opaque context passed to <PoolCreate>. data - Pointer to the DB_CONTEXT structure. Return Values: None. --*/ static VOID FCALL ConnectionClose(VOID *context, VOID *data) { DB_CONTEXT *db = data; DWORD i; UNREFERENCED_PARAMETER(context); ASSERT(data != NULL); TRACE("context=%p data=%p", context, data); // Free pre-compiled statement structures for (i = 0; i < ELEMENT_COUNT(db->stmt); i++) { if (db->stmt[i] != NULL) { mysql_stmt_close(db->stmt[i]); } } // Free handle structure if (db->handle != NULL) { mysql_close(db->handle); } // Free context structure ZeroMemory(db, sizeof(DB_CONTEXT)); MemFree(db); }
void test_empty_list_within_non_empty_list(void) { TEST_IGNORE(); // delete this line to run test int base_list[] = { 1, 2, 3 }; TEST_ASSERT_EQUAL(SUBLIST, check_lists(NULL, base_list, 0, ELEMENT_COUNT(base_list))); }
void test_non_empty_list_contains_empty_list(void) { TEST_IGNORE(); int list_to_compare[] = { 1, 2, 3 }; TEST_ASSERT_EQUAL(SUPERLIST, check_lists(list_to_compare, NULL, ELEMENT_COUNT(list_to_compare), 0)); }
DWORD FileGroupCreate(INT32 groupId, GROUPFILE *groupFile) { CHAR *defaultPath = NULL; CHAR *targetPath = NULL; CHAR buffer[12]; DWORD result = ERROR_SUCCESS; ASSERT(groupId != -1); ASSERT(groupFile != NULL); TRACE("groupId=%d groupFile=%p", groupId, groupFile); // Retrieve default location defaultPath = Io_ConfigGetPath("Locations", "Group_Files", "Default.Group", NULL); if (defaultPath == NULL) { TRACE("Unable to retrieve default file location."); return ERROR_NOT_ENOUGH_MEMORY; } // Retrieve target location StringCchPrintfA(buffer, ELEMENT_COUNT(buffer), "%i", groupId); targetPath = Io_ConfigGetPath("Locations", "Group_Files", buffer, NULL); if (targetPath == NULL) { TRACE("Unable to retrieve group file location."); Io_Free(defaultPath); return ERROR_NOT_ENOUGH_MEMORY; } // Copy default file to target file if (!CopyFileA(defaultPath, targetPath, FALSE)) { result = GetLastError(); TRACE("Unable to copy file \"%s\" to \"%s\" (error %lu).", defaultPath, targetPath, result); } else { // Open new group file result = FileGroupOpen(groupId, groupFile); if (result != ERROR_SUCCESS) { TRACE("Unable to open group file (error %lu).", result); } } Io_Free(defaultPath); Io_Free(targetPath); return result; }
DWORD FileGroupOpen(INT32 groupId, GROUPFILE *groupFile) { CHAR buffer[12]; CHAR *path; DWORD result; MOD_CONTEXT *mod; ASSERT(groupId != -1); ASSERT(groupFile != NULL); TRACE("groupId=%d groupFile=%p", groupId, groupFile); // Check if ioFTPD wiped out the module context pointer ASSERT(groupFile->lpInternal != NULL); mod = groupFile->lpInternal; // There must not be an existing file handle ASSERT(mod->file == INVALID_HANDLE_VALUE); // Retrieve group file location StringCchPrintfA(buffer, ELEMENT_COUNT(buffer), "%i", groupId); path = Io_ConfigGetPath("Locations", "Group_Files", buffer, NULL); if (path == NULL) { TRACE("Unable to retrieve file location."); return ERROR_NOT_ENOUGH_MEMORY; } // Open group file mod->file = CreateFileA(path, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL); if (mod->file != INVALID_HANDLE_VALUE) { result = ERROR_SUCCESS; } else { result = GetLastError(); TRACE("Unable to open file \"%s\" (error %lu).", path, result); } Io_Free(path); return result; }
/*++ ConnectionOpen Opens a server connection. Arguments: context - Opaque context passed to <PoolCreate>. data - Pointer to a pointer that receives the DB_CONTEXT structure. Return Values: If the function succeeds, the return value is nonzero (true). If the function fails, the return value is zero (false). --*/ static BOOL FCALL ConnectionOpen(VOID *context, VOID **data) { DB_CONTEXT *db; DB_CONFIG_SERVER *server; DWORD error; DWORD i; INT attempt; INT attemptMax; LONG serverIndex; LONG serverNextIndex; MYSQL *connection; my_bool optReconnect; UINT optTimeout; UNREFERENCED_PARAMETER(context); ASSERT(data != NULL); TRACE("context=%p data=%p", context, data); db = MemAllocate(sizeof(DB_CONTEXT)); if (db == NULL) { LOG_ERROR("Unable to allocate memory for database context."); error = ERROR_NOT_ENOUGH_MEMORY; goto failed; } ZeroMemory(db, sizeof(DB_CONTEXT)); // // Have the MySQL client library allocate the handle structure for us. This is // in case the MYSQL structure changes in a future version of the client library. // db->handle = mysql_init(NULL); if (db->handle == NULL) { LOG_ERROR("Unable to allocate memory for MySQL handle."); error = ERROR_NOT_ENOUGH_MEMORY; goto failed; } // If the maximum number of attempts were not specified, try all servers if (dbConfigGlobal.connAttempts > 0) { attemptMax = dbConfigGlobal.connAttempts; } else { attemptMax = dbConfigServerCount; } for (attempt = 0; attempt < attemptMax; attempt++) { // Use the most recent server for the connection attempt serverIndex = dbIndex; server = &dbConfigServers[serverIndex]; TRACE("Connecting to server #%d [%s] on attempt %lu/%lu.", serverIndex, server->name, attempt+1, attemptMax); // Set connection options optTimeout = (UINT)dbConfigGlobal.connTimeout; if (mysql_options(db->handle, MYSQL_OPT_CONNECT_TIMEOUT, &optTimeout) != 0) { TRACE("Failed to set connection timeout option."); } optReconnect = FALSE; if (mysql_options(db->handle, MYSQL_OPT_RECONNECT, &optReconnect) != 0) { TRACE("Failed to set reconnection option."); } if (server->compression) { if (mysql_options(db->handle, MYSQL_OPT_COMPRESS, 0) != 0) { TRACE("Failed to set compression option."); } } if (server->sslEnable) { // // This function always returns 0. If the SSL setup is incorrect, // the call to mysql_real_connect() will return an error. // mysql_ssl_set(db->handle, server->sslKeyFile, server->sslCertFile, server->sslCAFile, server->sslCAPath, server->sslCiphers); } // Attempt connection with server connection = mysql_real_connect(db->handle, server->host, server->user, server->password, server->database, server->port, NULL, CLIENT_INTERACTIVE); if (connection == NULL) { LOG_ERROR("Unable to connect to server [%s]: %s", server->name, mysql_error(db->handle)); } else if (mysql_get_server_version(db->handle) < 50019) { LOG_ERROR("Unsupported version of MySQL Server [%s]: running v%s, must be v5.0.19 or newer.", server->name, mysql_get_server_info(db->handle)); } else { // Pointer values should be the same as from mysql_init() ASSERT(connection == db->handle); // Allocate pre-compiled statement structures for (i = 0; i < ELEMENT_COUNT(db->stmt); i++) { db->stmt[i] = mysql_stmt_init(db->handle); if (db->stmt[i] == NULL) { LOG_ERROR("Unable to allocate memory for statement structure."); error = ERROR_NOT_ENOUGH_MEMORY; goto failed; } } // Successfully connected, set the global server index InterlockedExchange(&dbIndex, serverIndex); // Update context's server index and time stamps db->index = serverIndex; GetSystemTimeAsFileTime(&db->created.fileTime); db->used.value = db->created.value; LOG_INFO("Connected to %s [%s], running MySQL Server v%s.", mysql_get_host_info(db->handle), server->name, mysql_get_server_info(db->handle)); *data = db; return TRUE; } // Unsuccessful connection, continue to the next server serverNextIndex = serverIndex + 1; if (serverNextIndex >= (LONG)dbConfigServerCount) { serverNextIndex = 0; } // // Compare the current server index before swapping values in the // event that another thread has already changed the index. // InterlockedCompareExchange(&dbIndex, serverNextIndex, serverIndex); } // Unable to connect to any servers error = ERROR_CONNECTION_REFUSED; failed: if (db != NULL) { ConnectionClose(NULL, db); } SetLastError(error); return FALSE; }