summaryrefslogtreecommitdiffstats
path: root/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main.c')
-rw-r--r--main.c376
1 files changed, 0 insertions, 376 deletions
diff --git a/main.c b/main.c
deleted file mode 100644
index b52e32d..0000000
--- a/main.c
+++ /dev/null
@@ -1,376 +0,0 @@
-#include <stdint.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/mman.h>
-#include <sys/time.h>
-#include <time.h>
-
-#include <zlib.h>
-
-#include <assert.h>
-
-#include "GenericList.h"
-
-#define C4GroupMaxMaker 30
-#define C4GroupMaxPassword 30
-
-typedef struct {
- char id[25];
- uint8_t Reserved1[3];
- int32_t Ver1, Ver2;
- int32_t Entries;
- char Maker[C4GroupMaxMaker + 2];
- char Password[C4GroupMaxPassword + 2];
- int32_t Creation;
- int32_t Original;
- uint8_t Reserved2[92];
-} __attribute__((__packed__)) C4GroupHeader;
-
-typedef struct {
- char FileName[257];
- uint8_t Reserved1[3];
- int32_t Packed;
- int32_t Directory;
- int32_t Size;
- int32_t Reserved2;
- int32_t Offset;
- int32_t Modified;
- uint8_t HasCRC;
- uint32_t CRC;
- uint8_t Executable;
- uint8_t Reserved3[26];
-} __attribute__((__packed__)) C4GroupEntryCore;
-
-struct list_GroupEntryList;
-typedef struct {
- C4GroupEntryCore core;
- uint8_t* data;
- struct list_GroupEntryList* children;
-} C4GroupEntryData;
-
-LIST_AUTO(C4GroupEntryData, GroupEntryList)
-#define ForeachGroupEntry(list) LIST_FOREACH(GroupEntryList, list, entry)
-
-off_t fileSizeFd(int fd)
-{
- struct stat st;
-
- if(fstat(fd, &st) == -1)
- {
- return -1;
- }
-
- return st.st_size;
-}
-
-void memScrambleHeader(uint8_t* data)
-{
- // XOR deface
- for(size_t i = 0; i < sizeof(C4GroupHeader); i++)
- data[i] ^= 237;
- // byte swap
- for(size_t i = 0; i + 2 < sizeof(C4GroupHeader); i += 3)
- {
- uint8_t temp = data[i];
- data[i] = data[i + 2];
- data[i + 2] = temp;
- }
-}
-
-void buildChildren(C4GroupEntryData* entry)
-{
- C4GroupHeader* header = (C4GroupHeader*)entry->data;
-
- entry->children = GroupEntryListNew();
-
- uint8_t* data = entry->data + sizeof(C4GroupHeader);
- uint8_t* childData = entry->data + sizeof(C4GroupHeader) + sizeof(C4GroupEntryCore) * header->Entries;
-
- for(size_t i = 0; i < (size_t)header->Entries; ++i)
- {
- C4GroupEntryCore* core = (C4GroupEntryCore*)(data + sizeof(C4GroupEntryCore) * i);
- C4GroupEntryData* childEntry = &GroupEntryListAppend(entry->children, (C4GroupEntryData){.core = *core, .data = childData + core->Offset, .children = NULL})->value;
-
- if(core->Directory)
- {
- memScrambleHeader(childEntry->data);
- buildChildren(childEntry);
- }
- }
-}
-
-const char* formatTime(int32_t time)
-{
- time_t tTime = time;
- static char ret[128];
- strftime(ret, sizeof(ret), "%c", localtime(&tTime));
- return ret;
-}
-
-void handleChildren(GroupEntryList* entries, size_t indent, const char* path)
-{
- size_t pathLen = strlen(path);
- char* targetPath = malloc(pathLen + 260 + 1);
-
- strcpy(targetPath, path);
- strcpy(targetPath + pathLen++, "/");
-
- if(mkdir(path, 0755) == -1)
- {
- fprintf(stderr, "ERROR: Creating target directory \"%s\": %s\n", path, strerror(errno));
- goto ret;
- }
-
- ForeachGroupEntry(entries)
- {
- for(size_t i = 0; i < indent; ++i)
- {
- putchar('\t');
- }
-
- strcpy(targetPath + pathLen, entry->value.core.FileName);
-
-// printf("%s\t%s\t%d B\n", targetPath, formatTime(entry->value.core.Modified), entry->value.core.Size);
-
- if(!entry->value.core.Directory)
- {
- int file = open(targetPath, O_WRONLY | O_CREAT, entry->value.core.Executable ? 0755 : 0644);
- if(file == -1)
- {
- fprintf(stderr, "ERROR: Creating target file \"%s\": %s\n", targetPath, strerror(errno));
- goto ret;
- }
- write(file, entry->value.data, entry->value.core.Size);
-
- if(close(file) == -1)
- {
- fprintf(stderr, "ERROR: Closing file \"%s\": %s\n", targetPath, strerror(errno));
- }
-
- struct timeval tv[2] = {{.tv_usec = 0, .tv_sec = entry->value.core.Modified}, {.tv_usec = 0, .tv_sec = entry->value.core.Modified}};
- if(utimes(targetPath, tv) == -1)
- {
- fprintf(stderr, "ERROR: Setting modification time for \"%s\": %s\n", targetPath, strerror(errno));
- }
- }
-
- if(entry->value.core.Directory)
- {
- handleChildren(entry->value.children, indent + 1, targetPath);
- }
- }
-
-ret:
- free(targetPath);
-}
-
-void deleteChildren(GroupEntryList* entries)
-{
- ForeachGroupEntry(entries)
- {
- if(entry->value.core.Directory)
- {
- deleteChildren(entry->value.children);
- }
- }
-
- GroupEntryListDestroy(entries);
-}
-
-int main(int argc, char* argv[])
-{
- if(argc != 3)
- {
- fprintf(stderr, "USAGE: %s <group> <target>\n", argv[0]);
- return EXIT_FAILURE;
- }
-
- int file = open(argv[1], O_RDONLY);
- if(file == -1)
- {
- fprintf(stderr, "ERROR: Opening file \"%s\": %s\n", argv[1], strerror(errno));
- return EXIT_FAILURE;
- }
-
- __off_t size = fileSizeFd(file);
- if(size == -1)
- {
- fprintf(stderr, "ERROR: Getting file size: %s\n", strerror(errno));
- return EXIT_FAILURE;
- }
- else
- {
- printf("Size: %ld\n", size);
- }
-
- uint8_t* mappedFile = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, file, 0);
-
- if(mappedFile == MAP_FAILED)
- {
- fprintf(stderr, "ERROR: Mapping file: %s\n", strerror(errno));
- return EXIT_FAILURE;
- }
-
- if(close(file) == -1)
- {
- fprintf(stderr, "ERROR: Closing file: %s\n", strerror(errno));
- return EXIT_FAILURE;
- }
-
- if((mappedFile[0] != 0x1e && mappedFile[0] != 0x1f) || (mappedFile[1] != 0x8c && mappedFile[1] != 0x8b))
- {
- fprintf(stderr, "ERROR: The file is not a valid group file. Magic bytes don't match.\n");
- return EXIT_FAILURE;
- }
-
- mappedFile[0] = 0x1f;
- mappedFile[1] = 0x8b;
-
- z_stream strm = {
- .zalloc = NULL,
- .zfree = NULL,
- .opaque = NULL,
- .next_in = mappedFile,
- .avail_in = size
- };
-
- int ret = inflateInit2(&strm, 15 + 16); // window size 15 + automatic gzip
-
- if(ret != Z_OK)
- {
- fprintf(stderr, "ERROR: inflateInit2: %s\n", zError(ret));
- return EXIT_FAILURE;
- }
-
- size_t currentSize = sizeof(C4GroupHeader);
- C4GroupHeader* header = malloc(currentSize);
-
- strm.next_out = (Bytef*)header;
- strm.avail_out = currentSize;
-
- ret = inflate(&strm, Z_SYNC_FLUSH);
- if(ret != Z_OK)
- {
- fprintf(stderr, "ERROR: inflating header: %s\n", zError(ret));
- return EXIT_FAILURE;
- }
-
- memScrambleHeader((uint8_t*)header);
-
- printf("Version %d.%d\n", header->Ver1, header->Ver2);
- printf("%d Entries\n", header->Entries);
- printf("%sOriginal\n", header->Original == 1234567 ? "" : "Not ");
- printf("Created %s\n", formatTime(header->Creation));
- puts(header->id);
- puts(header->Maker);
-
- assert(header->Ver1 == 1);
- assert(header->Ver2 == 2);
-
- currentSize += sizeof(C4GroupEntryCore) * header->Entries;
- header = realloc(header, currentSize);
- C4GroupEntryCore* cores = (C4GroupEntryCore*)((void*)(header) + sizeof(C4GroupHeader));
-
- GroupEntryList* entries = GroupEntryListNew();
-
- strm.next_out = (Bytef*)cores;
- strm.avail_out = sizeof(C4GroupEntryCore) * header->Entries;
-
- ret = inflate(&strm, Z_SYNC_FLUSH);
- if(ret != Z_OK)
- {
- fprintf(stderr, "ERROR: inflating header: %s\n", zError(ret));
- return EXIT_FAILURE;
- }
-
- C4GroupEntryCore* last = cores + header->Entries - 1;
- size_t uncompressedSize = last->Offset + last->Size;
-
- currentSize += uncompressedSize;
-
-#define TMP_FILE "cc4group.tmp"
- int tmpFile = open(TMP_FILE, O_CREAT | O_RDWR | O_TRUNC | O_EXCL, 0600);
- if(tmpFile == -1)
- {
- fprintf(stderr, "ERROR: Opening tmp file \"%s\": %s\n", "cc4group.tmp", strerror(errno));
- return EXIT_FAILURE;
- }
-
- if(unlink(TMP_FILE) == -1)
- {
- fprintf(stderr, "ERROR: Deleting tmp file \"%s\". Manual deletion is required: %s\n", TMP_FILE, strerror(errno));
- }
-#undef TMP_FILE
-
- // allocate file size
- // https://gist.github.com/marcetcheverry/991042
- if(lseek(tmpFile, currentSize - 1, SEEK_SET) == -1)
- {
- fprintf(stderr, "ERROR: Seeking the tmp file to the end: %s\n", strerror(errno));
- return EXIT_FAILURE;
- }
-
- if(write(tmpFile, "", 1) == -1)
- {
- fprintf(stderr, "ERROR: Writing to the tmp file's end: %s\n", strerror(errno));
- return EXIT_FAILURE;
- }
-
- uint8_t* mmappedHeader = mmap(NULL, currentSize, PROT_READ | PROT_WRITE, MAP_SHARED, tmpFile, 0);
- if(mmappedHeader == MAP_FAILED)
- {
- fprintf(stderr, "ERROR: Mapping tmp file: %s\n", strerror(errno));
- return EXIT_FAILURE;
- }
-
- if(close(tmpFile) == -1)
- {
- fprintf(stderr, "ERROR: Closing tmp file \"cc4group.tmp\": %s\n", strerror(errno));
- return EXIT_FAILURE;
- }
-
- uint8_t* data = (void*)(mmappedHeader) + sizeof(C4GroupHeader) + sizeof(C4GroupEntryCore) * header->Entries;
-
- // write alredy decompressed header and cores into the file
- memcpy(mmappedHeader, header, data - mmappedHeader);
-
- strm.next_out = data;
- strm.avail_out = uncompressedSize;
-
- ret = inflate(&strm, Z_SYNC_FLUSH);
- if(ret != Z_STREAM_END)
- {
- fprintf(stderr, "ERROR: inflating header: %s\n", zError(ret));
- return EXIT_FAILURE;
- }
-
- inflateEnd(&strm);
-
- if(munmap(mappedFile, size) == -1)
- {
- fprintf(stderr, "ERROR: Unmapping file: %s\n", strerror(errno));
- return EXIT_FAILURE;
- }
-
- C4GroupEntryData root = {.data = (uint8_t*)mmappedHeader, .children = NULL};
- buildChildren(&root);
-
- handleChildren(root.children, 0, argv[2]);
-
- deleteChildren(entries);
-
- free(header);
-
- if(munmap(mmappedHeader, size) == -1)
- {
- fprintf(stderr, "ERROR: Unmapping tmp file: %s\n", strerror(errno));
- return EXIT_FAILURE;
- }
-
- return EXIT_SUCCESS;
-}