#include #include #include #include #define BUFFER_SIZE 4096 #define MAX_LINE_LENGTH 1024 typedef struct { DWORD attributes; FILETIME creationTime; FILETIME lastAccessTime; FILETIME lastWriteTime; DWORD fileSizeHigh; DWORD fileSizeLow; } FileAttributes; void splitString(const char* str, char*** lines, int* lineCount) { *lineCount = 0; *lines = NULL; const char* start = str; const char* current = str; while (*current) { if (*current == '\r' || *current == '\n') { size_t length = current - start; if (length > 0) { *lines = realloc(*lines, (*lineCount + 1) * sizeof(char*)); (*lines)[*lineCount] = malloc(length + 1); strncpy((*lines)[*lineCount], start, length); (*lines)[*lineCount][length] = '\0'; (*lineCount)++; } if (*current == '\r' && *(current + 1) == '\n') { current++; } start = current + 1; } current++; } size_t remaining = current - start; if (remaining > 0) { *lines = realloc(*lines, (*lineCount + 1) * sizeof(char*)); (*lines)[*lineCount] = malloc(remaining + 1); strncpy((*lines)[*lineCount], start, remaining); (*lines)[*lineCount][remaining] = '\0'; (*lineCount)++; } } void freeLines(char** lines, int lineCount) { for (int i = 0; i < lineCount; i++) { free(lines[i]); } free(lines); } char* fileTimeToString(const FILETIME* ft) { if (ft->dwLowDateTime == 0 && ft->dwHighDateTime == 0) { return strdup("N/A"); } SYSTEMTIME st; FileTimeToSystemTime(ft, &st); char* buffer = malloc(64); snprintf(buffer, 64, "%02d.%02d.%04d %02d:%02d:%02d", st.wDay, st.wMonth, st.wYear, st.wHour, st.wMinute, st.wSecond); return buffer; } char* attributesToString(DWORD attrs) { if (attrs == INVALID_FILE_ATTRIBUTES) { return strdup("Invalid attributes"); } char* result = calloc(256, 1); int first = 1; #define ADD_ATTR(attr, name) \ if (attrs & attr) { \ if (!first) strcat(result, ", "); \ strcat(result, name); \ first = 0; \ } ADD_ATTR(FILE_ATTRIBUTE_ARCHIVE, "Archive"); ADD_ATTR(FILE_ATTRIBUTE_COMPRESSED, "Compressed"); ADD_ATTR(FILE_ATTRIBUTE_DIRECTORY, "Directory"); ADD_ATTR(FILE_ATTRIBUTE_ENCRYPTED, "Encrypted"); ADD_ATTR(FILE_ATTRIBUTE_HIDDEN, "Hidden"); ADD_ATTR(FILE_ATTRIBUTE_NORMAL, "Normal"); ADD_ATTR(FILE_ATTRIBUTE_OFFLINE, "Offline"); ADD_ATTR(FILE_ATTRIBUTE_READONLY, "Readonly"); ADD_ATTR(FILE_ATTRIBUTE_SYSTEM, "System"); ADD_ATTR(FILE_ATTRIBUTE_TEMPORARY, "Temporary"); #undef ADD_ATTR return result; } FileAttributes getFileAttributesWin(const char* filePath) { FileAttributes attrs = {0}; WIN32_FILE_ATTRIBUTE_DATA fileInfo; if (GetFileAttributesExA(filePath, GetFileExInfoStandard, &fileInfo)) { attrs.attributes = fileInfo.dwFileAttributes; attrs.creationTime = fileInfo.ftCreationTime; attrs.lastAccessTime = fileInfo.ftLastAccessTime; attrs.lastWriteTime = fileInfo.ftLastWriteTime; attrs.fileSizeHigh = fileInfo.nFileSizeHigh; attrs.fileSizeLow = fileInfo.nFileSizeLow; } else { attrs.attributes = INVALID_FILE_ATTRIBUTES; } return attrs; } void runChildProcess(const char* handleStr) { printf("Child process started.\n"); HANDLE hFile = (HANDLE)(INT_PTR)atoll(handleStr); char buffer[BUFFER_SIZE]; DWORD bytesRead; char* totalData = calloc(1, 1); size_t totalSize = 0; while (ReadFile(hFile, buffer, sizeof(buffer), &bytesRead, NULL) && bytesRead > 0) { totalData = realloc(totalData, totalSize + bytesRead + 1); memcpy(totalData + totalSize, buffer, bytesRead); totalSize += bytesRead; totalData[totalSize] = '\0'; } CloseHandle(hFile); char** lines = NULL; int lineCount = 0; splitString(totalData, &lines, &lineCount); free(totalData); for (int i = 0; i < lineCount; i++) { if (strlen(lines[i]) == 0) continue; FileAttributes attrs = getFileAttributesWin(lines[i]); ULONGLONG fileSize = ((ULONGLONG)attrs.fileSizeHigh << 32) | attrs.fileSizeLow; char* attrStr = attributesToString(attrs.attributes); char* createdStr = fileTimeToString(&attrs.creationTime); char* accessedStr = fileTimeToString(&attrs.lastAccessTime); char* modifiedStr = fileTimeToString(&attrs.lastWriteTime); printf("\nFile: %s\n", lines[i]); printf("Attributes: %s\n", attrStr); printf("Size: %llu bytes\n", fileSize); printf("Created: %s\n", createdStr); printf("Last accessed: %s\n", accessedStr); printf("Last modified: %s\n", modifiedStr); free(attrStr); free(createdStr); free(accessedStr); free(modifiedStr); } freeLines(lines, lineCount); } void runParentProcess() { printf("Parent process started.\n"); SECURITY_ATTRIBUTES sa = {0}; sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.bInheritHandle = FALSE; HANDLE hFile = CreateFileA( "test.txt", GENERIC_READ, FILE_SHARE_READ, &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if (hFile == INVALID_HANDLE_VALUE) { fprintf(stderr, "Error opening file. Error: %lu\n", GetLastError()); return; } if (!SetHandleInformation(hFile, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)) { fprintf(stderr, "Failed to set handle inheritance. Error: %lu\n", GetLastError()); CloseHandle(hFile); return; } char cmdLine[256]; snprintf(cmdLine, sizeof(cmdLine), "%s child %lld", GetCommandLineA(), (long long)(INT_PTR)hFile); STARTUPINFOA si = {0}; si.cb = sizeof(si); PROCESS_INFORMATION pi = {0}; if (!CreateProcessA( NULL, cmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) { fprintf(stderr, "Error creating child process. Error: %lu\n", GetLastError()); CloseHandle(hFile); return; } CloseHandle(pi.hProcess); CloseHandle(pi.hThread); CloseHandle(hFile); } int main(int argc, char* argv[]) { if (argc == 1) { runParentProcess(); } else if (argc == 3 && strcmp(argv[1], "child") == 0) { runChildProcess(argv[2]); } else { fprintf(stderr, "Invalid arguments.\n"); return 1; } return 0; }