diff options
| -rw-r--r-- | CMakeLists.txt | 22 | ||||
| -rw-r--r-- | examples/c4cat.c | 7 | ||||
| -rw-r--r-- | examples/c4ls.c | 8 | ||||
| -rw-r--r-- | src/cc4group.c | 37 | ||||
| -rw-r--r-- | src/platform/platform.h | 32 | ||||
| -rw-r--r-- | src/platform/unix.c | 13 | ||||
| -rw-r--r-- | src/platform/windows.c | 108 |
7 files changed, 201 insertions, 26 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index de40a0f..0adbb46 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,10 +13,20 @@ endif() find_package(ZLIB REQUIRED) + +if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") + set(CC4GROUP_PLATFORM "windows") +else() + set(CC4GROUP_PLATFORM "unix") +endif() + +string(TOUPPER ${CC4GROUP_PLATFORM} CC4GROUP_PLATFORM_DEF) + set(cc4group_SRC src/cc4group.c src/c4groupheader.c src/c4groupentrycore.c + src/platform/${CC4GROUP_PLATFORM}.c ) set(cppc4group_SRC @@ -26,6 +36,7 @@ set(cppc4group_SRC add_library(cc4group_objs OBJECT ${cc4group_SRC}) set_property(TARGET cc4group_objs PROPERTY POSITION_INDEPENDENT_CODE ON) target_include_directories(cc4group_objs PRIVATE ZLIB::ZLIB) +target_compile_definitions(cc4group_objs PRIVATE CC4GROUP_PLATFORM_${CC4GROUP_PLATFORM_DEF}) add_library(cc4group STATIC $<TARGET_OBJECTS:cc4group_objs>) target_link_libraries(cc4group PRIVATE ZLIB::ZLIB) @@ -45,7 +56,6 @@ function(example name) endfunction() example(unc4group) -example(c4cat) example(c4copy) example(c4info) example(c4ls) @@ -53,5 +63,11 @@ example(c4touch) example(c4rm) example(c4mkdir) -add_executable(c4cat_dyn examples/c4cat_dyn.c) -target_link_libraries(c4cat_dyn PRIVATE -ldl) +add_executable(c4cat examples/c4cat.c src/platform/${CC4GROUP_PLATFORM}.c) +target_link_libraries(c4cat PRIVATE cc4group) +target_compile_definitions(c4cat PRIVATE CC4GROUP_PLATFORM_${CC4GROUP_PLATFORM_DEF}) + +if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Windows") + add_executable(c4cat_dyn examples/c4cat_dyn.c) + target_link_libraries(c4cat_dyn PRIVATE -ldl) +endif() diff --git a/examples/c4cat.c b/examples/c4cat.c index 04f51b6..3da506e 100644 --- a/examples/c4cat.c +++ b/examples/c4cat.c @@ -3,11 +3,11 @@ #include <errno.h> #include <string.h> #include <sys/stat.h> -#include <sys/mman.h> #include <fcntl.h> #include <unistd.h> #include "cc4group.h" +#include "platform/platform.h" bool catNormalFile(const char* const path, const off_t size) { @@ -18,7 +18,8 @@ bool catNormalFile(const char* const path, const off_t size) return false; } - void* mappedFile = mmap(NULL, size, PROT_READ, MAP_PRIVATE, file, 0); + void* extra; + void* mappedFile = cc4group_mmap(NULL, size, PROT_READ, MAP_PRIVATE, file, 0, &extra); if(close(file) == -1) { @@ -36,7 +37,7 @@ bool catNormalFile(const char* const path, const off_t size) fprintf(stderr, "ERROR: Writing file contents of \"%s\" to stdout: %s\n", path, strerror(errno)); } - if(munmap(mappedFile, size) == -1) + if(cc4group_munmap(mappedFile, size, extra) == -1) { fprintf(stderr, "ERROR: Unmapping \"%s\": %s\n", path, strerror(errno)); } diff --git a/examples/c4ls.c b/examples/c4ls.c index 4324d9b..ce2f996 100644 --- a/examples/c4ls.c +++ b/examples/c4ls.c @@ -13,19 +13,19 @@ const char* formatTime(int32_t time) return ret; } -const char* formatSize(size_t size) +const char* formatSize(uint32_t size) { static char ret[128]; if(size < 1000) { - snprintf(ret, 128, "%4zd", size); + snprintf(ret, 128, "%4ud", size); return ret; } static const char prefixes[] = " KMGTPE"; const char* prefix = prefixes; - size_t fract = 0; + uint32_t fract = 0; while(size >= 1000 && *(prefix + 1) != '\0') { @@ -40,7 +40,7 @@ const char* formatSize(size_t size) } else { - snprintf(ret, 128, "%3zd%c", size, *prefix); + snprintf(ret, 128, "%3u%c", size, *prefix); } return ret; diff --git a/src/cc4group.c b/src/cc4group.c index 1a8c344..fb2036e 100644 --- a/src/cc4group.c +++ b/src/cc4group.c @@ -10,14 +10,16 @@ #include "c4groupentrycore.h" #include "GenericList.h" +#include "platform/platform.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 <utime.h> #include <assert.h> #include <stdio.h> @@ -208,7 +210,7 @@ static void deleteChildren(GroupEntryList* const entries) GroupEntryListDestroy(entries); } -static void* cc4group_mapSizedWriteFd(CC4Group* const this, int fd, size_t size) +static void* cc4group_mapSizedWriteFd(CC4Group* const this, int fd, size_t size, void** extra) { // allocate file size // https://gist.github.com/marcetcheverry/991042 @@ -224,17 +226,18 @@ static void* cc4group_mapSizedWriteFd(CC4Group* const this, int fd, size_t size) return MAP_FAILED; } - return mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + return cc4group_mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0, extra); } typedef struct { void* addr; size_t size; + void* extra; } MunmapData; static void cc4group_unmapTmpMemoryFile(MunmapData* data) { - if(munmap(data->addr, data->size) == -1) + if(cc4group_munmap(data->addr, data->size, data->extra) == -1) { fprintf(stderr, "WARNING: munmap: Unmapping tempory file failed: %s\n", strerror(errno)); } @@ -246,7 +249,7 @@ static void* cc4group_createTmpMemoryFile(CC4Group* const this, const size_t siz { void* ret; #define TMP_FILE "cc4group.tmp" - int tmpFile = open(TMP_FILE, O_CREAT | O_RDWR | O_TRUNC | O_EXCL, 0600); + int tmpFile = open(TMP_FILE, O_CREAT | O_BINARY | O_RDWR | O_TRUNC | O_EXCL, 0600); if(tmpFile == -1) { SET_ERRNO_ERROR("open: Opening tmp file \"" TMP_FILE "\""); @@ -259,7 +262,8 @@ static void* cc4group_createTmpMemoryFile(CC4Group* const this, const size_t siz } #undef TMP_FILE - ret = cc4group_mapSizedWriteFd(this, tmpFile, size); + void* mmapExtra; + ret = cc4group_mapSizedWriteFd(this, tmpFile, size, &mmapExtra); if(ret == MAP_FAILED) { // error message is set in the method @@ -274,7 +278,7 @@ static void* cc4group_createTmpMemoryFile(CC4Group* const this, const size_t siz fprintf(stderr, "ERROR: allocating memory for cleanup data: %s\n", strerror(errno)); } - *unmapData = (MunmapData){ret, size}; + *unmapData = (MunmapData){ret, size, mmapExtra}; *cleanupJob = (CC4Group_CleanupJob){(CC4Group_CleanupFunc)cc4group_unmapTmpMemoryFile, unmapData}; } @@ -330,6 +334,7 @@ static void cc4group_uncompressGroup(CC4Group* const this) uint8_t* retData = NULL; C4GroupHeader* header = NULL; uint8_t* mappedFile = MAP_FAILED; + void* mapExtra; uint8_t* mappedTmpFile = NULL; bool inflateStarted = false; size_t currentSize = 0; @@ -344,7 +349,7 @@ static void cc4group_uncompressGroup(CC4Group* const this) int file = -1; for(;;) { - file = open(this->path, O_RDONLY); + file = open(this->path, O_RDONLY | O_BINARY); if(file != -1) { break; @@ -386,7 +391,7 @@ static void cc4group_uncompressGroup(CC4Group* const this) } off_t size = st.st_size; - mappedFile = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, file, 0); + mappedFile = cc4group_mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, file, 0, &mapExtra); if(close(file) == -1) { @@ -537,7 +542,7 @@ ret: if(mappedFile != MAP_FAILED) { - if(munmap(mappedFile, size) == -1) + if(cc4group_munmap(mappedFile, size, mapExtra) == -1) { fprintf(stderr, "WARNING: munmap: Unmapping the group file failed: %s\n", strerror(errno)); } @@ -814,7 +819,7 @@ static bool cc4group_extractEntry(CC4Group* const this, const C4GroupEntryData* assert(root); assert(!root->core.Directory); - int file = open(targetPath, O_WRONLY | O_CREAT | O_EXCL, root->core.Executable ? 0755 : 0644); + int file = open(targetPath, O_WRONLY | O_BINARY | O_CREAT | O_EXCL, root->core.Executable ? 0755 : 0644); if(file == -1) { SET_ERRNO_ERROR("open: Creating target file"); @@ -827,10 +832,10 @@ static bool cc4group_extractEntry(CC4Group* const this, const C4GroupEntryData* fprintf(stderr, "WARNING: close: Closing the extracted file \"%s\" failed: %s\n", targetPath, strerror(errno)); } - struct timeval tv[2] = {{.tv_usec = 0, .tv_sec = root->core.Modified}, {.tv_usec = 0, .tv_sec = root->core.Modified}}; - if(utimes(targetPath, tv) == -1) + struct utimbuf times = {.actime = root->core.Modified, .modtime = root->core.Modified}; + if(utime(targetPath, ×) == -1) { - fprintf(stderr, "WARNING: utimes: Setting modification time for \"%s\" failed: %s\n", targetPath, strerror(errno)); + fprintf(stderr, "WARNING: utime: Setting modification time for \"%s\" failed: %s\n", targetPath, strerror(errno)); } return true; @@ -861,7 +866,7 @@ static bool cc4group_extractChildren(CC4Group* const this, const C4GroupEntryDat if(root->core.Directory) { assert(root->children); - if(mkdir(tmpPath, 0755) == -1 /*&& errno != EEXIST*/) + if(cc4group_mkdir(tmpPath, 0755) == -1 /*&& errno != EEXIST*/) { SET_ERRNO_ERROR("mkdir: Creating target directory"); success = false; @@ -1184,7 +1189,7 @@ static bool cc4group_saveIt(CC4Group* const this, const char* const path, bool c assert(this); bool success = false; - int file = open(path, O_WRONLY | O_CREAT | (overwrite ? O_TRUNC : O_EXCL), 0644); + int file = open(path, O_WRONLY | O_BINARY | O_CREAT | (overwrite ? O_TRUNC : O_EXCL), 0644); if(file == -1) { diff --git a/src/platform/platform.h b/src/platform/platform.h new file mode 100644 index 0000000..aaa6138 --- /dev/null +++ b/src/platform/platform.h @@ -0,0 +1,32 @@ +#pragma once + +#include <stddef.h> +#include <sys/types.h> + +#ifdef CC4GROUP_PLATFORM_WINDOWS + #define PROT_READ 0x1 + #define PROT_WRITE 0x2 + /* This flag is only available in WinXP+ */ + #ifdef FILE_MAP_EXECUTE + #define PROT_EXEC 0x4 + #else + #define PROT_EXEC 0x0 + #define FILE_MAP_EXECUTE 0 + #endif + + #define MAP_SHARED 0x01 + #define MAP_PRIVATE 0x02 + #define MAP_ANONYMOUS 0x20 + #define MAP_ANON MAP_ANONYMOUS + #define MAP_FAILED ((void *) -1) + + #define cc4group_mkdir(path, mode) mkdir((path)) +#else + #include <sys/mman.h> + + #define cc4group_mkdir(path, mode) mkdir((path), (mode)) + #define O_BINARY 0 +#endif + +void *cc4group_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset, void** extra); +int cc4group_munmap(void *addr, size_t length, void* extra);
\ No newline at end of file diff --git a/src/platform/unix.c b/src/platform/unix.c new file mode 100644 index 0000000..ecf5166 --- /dev/null +++ b/src/platform/unix.c @@ -0,0 +1,13 @@ +#include "platform.h" + +void *cc4group_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset, void** extra) +{ + (void)extra; + return mmap(start, length, prot, flags, fd, offset); +} + +int cc4group_munmap(void *addr, size_t length, void* extra) +{ + (void)extra; + return munmap(addr, length); +} diff --git a/src/platform/windows.c b/src/platform/windows.c new file mode 100644 index 0000000..fb37837 --- /dev/null +++ b/src/platform/windows.c @@ -0,0 +1,108 @@ +/* mmap() replacement for Windows + * + * Author: Mike Frysinger <vapier@gentoo.org> + * Modified to not leak the CreateFileMapping-Handle, as well as fixed MAP_PRIVATE to actually work by Markus Mittendrein + * Placed into the public domain + */ + +/* References: + * CreateFileMapping: http://msdn.microsoft.com/en-us/library/aa366537(VS.85).aspx + * CloseHandle: http://msdn.microsoft.com/en-us/library/ms724211(VS.85).aspx + * MapViewOfFile: http://msdn.microsoft.com/en-us/library/aa366761(VS.85).aspx + * https://source.winehq.org/source/dlls/kernel32/virtual.c#0356 + * UnmapViewOfFile: http://msdn.microsoft.com/en-us/library/aa366882(VS.85).aspx + */ + +#include <io.h> +#include <windows.h> +#include <sys/types.h> + +#include <stdio.h> + +#include "platform.h" + +#ifdef __USE_FILE_OFFSET64 +# define DWORD_HI(x) (x >> 32) +# define DWORD_LO(x) ((x) & 0xffffffff) +#else +# define DWORD_HI(x) (0) +# define DWORD_LO(x) (x) +#endif + +void *cc4group_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset, void** extra) +{ + (void)start; + if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) + return MAP_FAILED; + if (fd == -1) { + if (!(flags & MAP_ANON) || offset) + return MAP_FAILED; + } else if (flags & MAP_ANON) + return MAP_FAILED; + + DWORD flProtect; + if (prot & PROT_WRITE) { + if (prot & PROT_EXEC) { + if(prot & MAP_PRIVATE) + flProtect = PAGE_EXECUTE_WRITECOPY; + else + flProtect = PAGE_EXECUTE_READWRITE; + } + else { + if(prot & MAP_PRIVATE) + flProtect = PAGE_WRITECOPY; + else + flProtect = PAGE_READWRITE; + } + } else if (prot & PROT_EXEC) { + if (prot & PROT_READ) + flProtect = PAGE_EXECUTE_READ; + else if (prot & PROT_EXEC) + flProtect = PAGE_EXECUTE; + } else + flProtect = PAGE_READONLY; + + off_t end = length + offset; + HANDLE mmap_fd, h; + if (fd == -1) + mmap_fd = INVALID_HANDLE_VALUE; + else + mmap_fd = (HANDLE)_get_osfhandle(fd); + h = CreateFileMapping(mmap_fd, NULL, flProtect, DWORD_HI(end), DWORD_LO(end), NULL); + if (h == NULL) + return MAP_FAILED; + + DWORD dwDesiredAccess; + if (flags & MAP_PRIVATE) + dwDesiredAccess = FILE_MAP_COPY; + else if (prot & PROT_WRITE) + dwDesiredAccess = FILE_MAP_WRITE; + else + dwDesiredAccess = FILE_MAP_READ; + if (prot & PROT_EXEC) + dwDesiredAccess |= FILE_MAP_EXECUTE; + if (flags & MAP_PRIVATE) + dwDesiredAccess |= FILE_MAP_COPY; + + void *ret = MapViewOfFile(h, dwDesiredAccess, DWORD_HI(offset), DWORD_LO(offset), length); + if (ret == NULL) { + CloseHandle(h); + ret = MAP_FAILED; + } + + *extra = h; + + return ret; +} + +int cc4group_munmap(void *addr, size_t length, void* extra) +{ + (void)length; + UnmapViewOfFile(addr); + CloseHandle(extra); + /* ruh-ro, we leaked handle from CreateFileMapping() ... */ + return 0; +} + +#undef DWORD_HI +#undef DWORD_LO |
