summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt22
-rw-r--r--examples/c4cat.c7
-rw-r--r--examples/c4ls.c8
-rw-r--r--src/cc4group.c37
-rw-r--r--src/platform/platform.h32
-rw-r--r--src/platform/unix.c13
-rw-r--r--src/platform/windows.c108
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, &times) == -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