summaryrefslogtreecommitdiff
path: root/src/internal/slibtool_mapfile_impl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/internal/slibtool_mapfile_impl.c')
-rw-r--r--src/internal/slibtool_mapfile_impl.c78
1 files changed, 78 insertions, 0 deletions
diff --git a/src/internal/slibtool_mapfile_impl.c b/src/internal/slibtool_mapfile_impl.c
new file mode 100644
index 0000000..e5d40d1
--- /dev/null
+++ b/src/internal/slibtool_mapfile_impl.c
@@ -0,0 +1,78 @@
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include "slibtool_mapfile_impl.h"
+
+static void slbt_munmap(void * addr, size_t size)
+{
+ if (addr) {
+ munmap(addr,size);
+ }
+}
+
+struct slbt_map_info * slbt_map_file(
+ int fdat,
+ const char * path,
+ uint32_t flags)
+{
+ int fd;
+ void * addr;
+ struct stat st;
+ uint32_t oflag;
+ uint32_t mprot;
+ struct slbt_map_info * mapinfo;
+
+ if ((flags & SLBT_MAP_INPUT) && (flags & SLBT_MAP_OUTPUT)) {
+ oflag = O_RDWR;
+ mprot = PROT_READ|PROT_WRITE;
+ } else if (flags & SLBT_MAP_INPUT) {
+ oflag = O_RDONLY;
+ mprot = PROT_READ;
+ } else if (flags & SLBT_MAP_OUTPUT) {
+ oflag = O_WRONLY;
+ mprot = PROT_WRITE;
+ } else {
+ errno = EINVAL;
+ return 0;
+ }
+
+ if ((fd = openat(fdat,path,oflag,0)) < 0)
+ return 0;
+
+ if (fstat(fd,&st) < 0) {
+ close(fd);
+ return 0;
+ }
+
+ addr = st.st_size
+ ? mmap(0,st.st_size,mprot,MAP_SHARED,fd,0)
+ : 0;
+
+ if (addr == MAP_FAILED) {
+ close(fd);
+ return 0;
+ }
+
+ if (!(mapinfo = malloc(sizeof(*mapinfo)))) {
+ close(fd);
+ slbt_munmap(addr,st.st_size);
+ return 0;
+ }
+
+ close(fd);
+
+ mapinfo->addr = addr;
+ mapinfo->size = st.st_size;
+
+ return mapinfo;
+}
+
+void slbt_unmap_file(struct slbt_map_info * mapinfo)
+{
+ slbt_munmap(mapinfo->addr,mapinfo->size);
+ free(mapinfo);
+}