]> git.ipfire.org Git - location/libloc.git/blame - src/stringpool.c
stringpool: Make functions properly private
[location/libloc.git] / src / stringpool.c
CommitLineData
62b83e6d
MT
1/*
2 libloc - A library to determine the location of someone on the Internet
3
4 Copyright (C) 2017 IPFire Development Team <info@ipfire.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15*/
16
17#include <errno.h>
18#include <stddef.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
6809d5ac
MT
22#include <sys/mman.h>
23#include <unistd.h>
62b83e6d 24
c12a1385
MT
25#include <libloc/libloc.h>
26#include <libloc/format.h>
27#include <libloc/private.h>
28#include <libloc/stringpool.h>
62b83e6d 29
0e974d4b
MT
30enum loc_stringpool_mode {
31 STRINGPOOL_DEFAULT,
32 STRINGPOOL_MMAP,
33};
34
62b83e6d
MT
35struct loc_stringpool {
36 struct loc_ctx* ctx;
62b83e6d 37 int refcount;
0e974d4b
MT
38
39 enum loc_stringpool_mode mode;
40
62b83e6d 41 char* data;
0e974d4b 42 ssize_t length;
62b83e6d 43
0e974d4b 44 char* pos;
62b83e6d
MT
45};
46
010fe9b6
MT
47static off_t loc_stringpool_get_offset(struct loc_stringpool* pool, const char* pos) {
48 if (pos < pool->data)
49 return -EFAULT;
50
51 if (pos > (pool->data + pool->length))
52 return -EFAULT;
53
54 return pos - pool->data;
55}
56
57static char* __loc_stringpool_get(struct loc_stringpool* pool, off_t offset) {
58 if (offset < 0 || offset >= pool->length)
59 return NULL;
60
61 return pool->data + offset;
62}
63
64static int loc_stringpool_grow(struct loc_stringpool* pool, size_t length) {
65 DEBUG(pool->ctx, "Growing string pool to %zu bytes\n", length);
66
67 // Save pos pointer
68 off_t pos = loc_stringpool_get_offset(pool, pool->pos);
69
70 // Reallocate data section
71 pool->data = realloc(pool->data, length);
72 if (!pool->data)
73 return -ENOMEM;
74
75 pool->length = length;
76
77 // Restore pos
78 pool->pos = __loc_stringpool_get(pool, pos);
79
80 return 0;
81}
82
83static off_t loc_stringpool_append(struct loc_stringpool* pool, const char* string) {
bf4ac66f 84 if (!string)
010fe9b6
MT
85 return -EINVAL;
86
87 DEBUG(pool->ctx, "Appending '%s' to string pool at %p\n", string, pool);
88
89 // Make sure we have enough space
90 int r = loc_stringpool_grow(pool, pool->length + strlen(string) + 1);
91 if (r) {
92 errno = r;
93 return -1;
94 }
95
96 off_t offset = loc_stringpool_get_offset(pool, pool->pos);
97
98 // Copy string byte by byte
99 while (*string)
100 *pool->pos++ = *string++;
101
102 // Terminate the string
103 *pool->pos++ = '\0';
104
105 return offset;
106}
107
acf44a73
MT
108static void loc_stringpool_free(struct loc_stringpool* pool) {
109 DEBUG(pool->ctx, "Releasing string pool %p\n", pool);
110 int r;
111
112 switch (pool->mode) {
113 case STRINGPOOL_DEFAULT:
114 if (pool->data)
115 free(pool->data);
116 break;
117
118 case STRINGPOOL_MMAP:
119 if (pool->data) {
120 r = munmap(pool->data, pool->length);
121 if (r)
122 ERROR(pool->ctx, "Could not unmap data at %p: %s\n",
123 pool->data, strerror(errno));
124 }
125 break;
126 }
127
128 loc_unref(pool->ctx);
129 free(pool);
130}
131
22d8abdc 132int loc_stringpool_new(struct loc_ctx* ctx, struct loc_stringpool** pool) {
0e974d4b
MT
133 struct loc_stringpool* p = calloc(1, sizeof(*p));
134 if (!p)
8d10d064 135 return 1;
0e974d4b
MT
136
137 p->ctx = loc_ref(ctx);
138 p->refcount = 1;
6809d5ac 139
0e974d4b 140 // Save mode
8d10d064 141 p->mode = STRINGPOOL_DEFAULT;
0e974d4b
MT
142
143 *pool = p;
6809d5ac
MT
144
145 return 0;
146}
147
0e974d4b
MT
148static int loc_stringpool_mmap(struct loc_stringpool* pool, FILE* f, size_t length, off_t offset) {
149 if (pool->mode != STRINGPOOL_MMAP)
150 return -EINVAL;
6809d5ac 151
5c57de03 152 DEBUG(pool->ctx, "Reading string pool starting from %jd (%zu bytes)\n", (intmax_t)offset, length);
6809d5ac 153
0e974d4b
MT
154 // Map file content into memory
155 pool->data = pool->pos = mmap(NULL, length, PROT_READ,
156 MAP_PRIVATE, fileno(f), offset);
2601e83e 157
0e974d4b
MT
158 // Store size of section
159 pool->length = length;
6809d5ac 160
0e974d4b 161 if (pool->data == MAP_FAILED)
acf44a73 162 return 1;
2601e83e
MT
163
164 return 0;
165}
166
22d8abdc 167int loc_stringpool_open(struct loc_ctx* ctx, struct loc_stringpool** pool,
0e974d4b 168 FILE* f, size_t length, off_t offset) {
acf44a73
MT
169 struct loc_stringpool* p = NULL;
170
171 // Allocate a new stringpool
172 int r = loc_stringpool_new(ctx, &p);
0e974d4b
MT
173 if (r)
174 return r;
62b83e6d 175
8d10d064
MT
176 // Change mode to mmap
177 p->mode = STRINGPOOL_MMAP;
178
0e974d4b 179 // Map data into memory
2a30e4de 180 if (length > 0) {
8d10d064 181 r = loc_stringpool_mmap(p, f, length, offset);
acf44a73
MT
182 if (r) {
183 loc_stringpool_free(p);
2a30e4de 184 return r;
acf44a73 185 }
2a30e4de 186 }
62b83e6d 187
acf44a73 188 *pool = p;
62b83e6d
MT
189 return 0;
190}
191
22d8abdc 192struct loc_stringpool* loc_stringpool_ref(struct loc_stringpool* pool) {
62b83e6d
MT
193 pool->refcount++;
194
195 return pool;
196}
197
22d8abdc 198struct loc_stringpool* loc_stringpool_unref(struct loc_stringpool* pool) {
62b83e6d
MT
199 if (--pool->refcount > 0)
200 return NULL;
201
202 loc_stringpool_free(pool);
203
204 return NULL;
205}
206
62b83e6d
MT
207static off_t loc_stringpool_get_next_offset(struct loc_stringpool* pool, off_t offset) {
208 const char* string = loc_stringpool_get(pool, offset);
1afe5545
MT
209 if (!string)
210 return offset;
62b83e6d
MT
211
212 return offset + strlen(string) + 1;
213}
214
22d8abdc 215const char* loc_stringpool_get(struct loc_stringpool* pool, off_t offset) {
0e974d4b 216 return __loc_stringpool_get(pool, offset);
62b83e6d
MT
217}
218
22d8abdc 219size_t loc_stringpool_get_size(struct loc_stringpool* pool) {
2601e83e
MT
220 return loc_stringpool_get_offset(pool, pool->pos);
221}
222
62b83e6d
MT
223static off_t loc_stringpool_find(struct loc_stringpool* pool, const char* s) {
224 if (!s || !*s)
225 return -EINVAL;
226
227 off_t offset = 0;
0e974d4b 228 while (offset < pool->length) {
62b83e6d
MT
229 const char* string = loc_stringpool_get(pool, offset);
230 if (!string)
231 break;
232
233 int r = strcmp(s, string);
234 if (r == 0)
235 return offset;
236
237 offset = loc_stringpool_get_next_offset(pool, offset);
238 }
239
240 return -ENOENT;
241}
242
22d8abdc 243off_t loc_stringpool_add(struct loc_stringpool* pool, const char* string) {
62b83e6d
MT
244 off_t offset = loc_stringpool_find(pool, string);
245 if (offset >= 0) {
5c57de03 246 DEBUG(pool->ctx, "Found '%s' at position %jd\n", string, (intmax_t)offset);
62b83e6d
MT
247 return offset;
248 }
249
250 return loc_stringpool_append(pool, string);
251}
252
22d8abdc 253void loc_stringpool_dump(struct loc_stringpool* pool) {
62b83e6d
MT
254 off_t offset = 0;
255
0e974d4b 256 while (offset < pool->length) {
62b83e6d
MT
257 const char* string = loc_stringpool_get(pool, offset);
258 if (!string)
259 break;
260
5c57de03 261 printf("%jd (%zu): %s\n", (intmax_t)offset, strlen(string), string);
62b83e6d
MT
262
263 offset = loc_stringpool_get_next_offset(pool, offset);
264 }
265}
2601e83e 266
22d8abdc 267size_t loc_stringpool_write(struct loc_stringpool* pool, FILE* f) {
2601e83e
MT
268 size_t size = loc_stringpool_get_size(pool);
269
8f5b676a 270 return fwrite(pool->data, sizeof(*pool->data), size, f);
2601e83e 271}