summaryrefslogtreecommitdiff
path: root/src/internal/slibtool_mapfile_impl.c
blob: 5df006b713678186b136e8add41cdb32ab88a6f1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/*******************************************************************/
/*  slibtool: a skinny libtool implementation, written in C        */
/*  Copyright (C) 2016--2021  Z. Gilboa                            */
/*  Released under the Standard MIT License; see COPYING.SLIBTOOL. */
/*******************************************************************/

#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>

#include "slibtool_errinfo_impl.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;
	mapinfo->mark = addr;
	mapinfo->cap  = &mapinfo->mark[st.st_size];

	return mapinfo;
}

void slbt_unmap_file(struct slbt_map_info * mapinfo)
{
	slbt_munmap(mapinfo->addr,mapinfo->size);
	free(mapinfo);
}

int  slbt_mapped_readline(
	const struct slbt_driver_ctx *	dctx,
	struct slbt_map_info *		mapinfo,
	char *				buf,
	size_t				buflen)
{
	const char * ch;
	const char * cap;
	const char * mark;
	const char * newline;
	size_t       len;

	mark = mapinfo->mark;
	cap  = mapinfo->cap;

	for (ch=mark, newline=0; ch<cap && !newline; ch++)
		if (*ch == '\n')
			newline = ch;

	len = ch - mark;

	if (newline && (buflen <= len))
		return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_FLOW_ERROR);

	if (!newline)
		return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_BAD_DATA);

	memcpy(buf,mark,len);
	buf[len] = 0;

	mapinfo->mark += len;

	return 0;
}