]>
git.ipfire.org Git - location/libloc.git/blob - src/stringpool.c
2 libloc - A library to determine the location of someone on the Internet
4 Copyright (C) 2017 IPFire Development Team <info@ipfire.org>
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.
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.
25 #include <libloc/libloc.h>
26 #include <libloc/format.h>
27 #include <libloc/private.h>
28 #include <libloc/stringpool.h>
30 struct loc_stringpool
{
34 // A file descriptor when we open an existing stringpool
40 // Mapped data (from mmap())
46 char buffer
[LOC_DATABASE_PAGE_SIZE
];
49 static off_t
loc_stringpool_get_offset(struct loc_stringpool
* pool
, const char* pos
) {
50 if (pos
< pool
->data
) {
55 if (pos
> (pool
->data
+ pool
->length
)) {
60 return pos
- pool
->data
;
63 static char* __loc_stringpool_get(struct loc_stringpool
* pool
, off_t offset
) {
67 if (offset
< 0 || offset
>= pool
->length
) {
72 // Return any data that we have in memory
74 return pool
->data
+ offset
;
76 // Otherwise read a block from file
77 bytes_read
= pread(pool
->fd
, pool
->buffer
, sizeof(pool
->buffer
),
78 pool
->offset
+ offset
);
82 ERROR(pool
->ctx
, "Could not read from string pool: %m\n");
86 // It is okay, if we did not read as much as we wanted, since we might be reading
87 // the last block which might be of an unknown size.
89 // Search for a complete string. If there is no NULL byte, the block is garbage.
90 char* end
= memchr(pool
->buffer
, bytes_read
, '\0');
94 // Return what's in the buffer
98 static int loc_stringpool_grow(struct loc_stringpool
* pool
, size_t length
) {
99 DEBUG(pool
->ctx
, "Growing string pool to %zu bytes\n", length
);
102 off_t pos
= loc_stringpool_get_offset(pool
, pool
->pos
);
104 // Reallocate data section
105 pool
->data
= realloc(pool
->data
, length
);
109 pool
->length
= length
;
112 pool
->pos
= __loc_stringpool_get(pool
, pos
);
117 static off_t
loc_stringpool_append(struct loc_stringpool
* pool
, const char* string
) {
123 DEBUG(pool
->ctx
, "Appending '%s' to string pool at %p\n", string
, pool
);
125 // Make sure we have enough space
126 int r
= loc_stringpool_grow(pool
, pool
->length
+ strlen(string
) + 1);
130 off_t offset
= loc_stringpool_get_offset(pool
, pool
->pos
);
132 // Copy string byte by byte
134 *pool
->pos
++ = *string
++;
136 // Terminate the string
142 static void loc_stringpool_free(struct loc_stringpool
* pool
) {
143 DEBUG(pool
->ctx
, "Releasing string pool %p\n", pool
);
150 // Unmap any mapped memory
151 if (pool
->mmapped_data
) {
152 r
= munmap(pool
->mmapped_data
, pool
->length
);
154 ERROR(pool
->ctx
, "Error unmapping string pool: %m\n");
156 if (pool
->mmapped_data
== pool
->data
)
164 loc_unref(pool
->ctx
);
168 int loc_stringpool_new(struct loc_ctx
* ctx
, struct loc_stringpool
** pool
) {
169 struct loc_stringpool
* p
= calloc(1, sizeof(*p
));
173 p
->ctx
= loc_ref(ctx
);
181 static int loc_stringpool_mmap(struct loc_stringpool
* pool
) {
183 char* p
= mmap(NULL
, pool
->length
, PROT_READ
, MAP_PRIVATE
, pool
->fd
, pool
->offset
);
185 if (p
== MAP_FAILED
) {
186 // Ignore if data hasn't been aligned correctly
190 ERROR(pool
->ctx
, "Could not mmap stringpool: %m\n");
194 // Store mapped memory area
195 pool
->data
= pool
->mmapped_data
= pool
->pos
= p
;
200 int loc_stringpool_open(struct loc_ctx
* ctx
, struct loc_stringpool
** pool
,
201 FILE* f
, size_t length
, off_t offset
) {
202 struct loc_stringpool
* p
= NULL
;
204 // Allocate a new stringpool
205 int r
= loc_stringpool_new(ctx
, &p
);
209 // Store offset and length
213 DEBUG(p
->ctx
, "Reading string pool starting from %jd (%zu bytes)\n",
214 (intmax_t)p
->offset
, p
->length
);
218 // Copy the file descriptor
221 ERROR(ctx
, "Could not duplicate file the file descriptor: %m\n");
226 // Map data into memory
228 r
= loc_stringpool_mmap(p
);
238 loc_stringpool_free(p
);
243 struct loc_stringpool
* loc_stringpool_ref(struct loc_stringpool
* pool
) {
249 struct loc_stringpool
* loc_stringpool_unref(struct loc_stringpool
* pool
) {
250 if (--pool
->refcount
> 0)
253 loc_stringpool_free(pool
);
258 const char* loc_stringpool_get(struct loc_stringpool
* pool
, off_t offset
) {
259 return __loc_stringpool_get(pool
, offset
);
262 size_t loc_stringpool_get_size(struct loc_stringpool
* pool
) {
263 return loc_stringpool_get_offset(pool
, pool
->pos
);
266 static off_t
loc_stringpool_find(struct loc_stringpool
* pool
, const char* s
) {
273 while (offset
< pool
->length
) {
274 const char* string
= loc_stringpool_get(pool
, offset
);
281 if (strcmp(s
, string
) == 0)
285 offset
+= strlen(string
) + 1;
293 off_t
loc_stringpool_add(struct loc_stringpool
* pool
, const char* string
) {
294 off_t offset
= loc_stringpool_find(pool
, string
);
296 DEBUG(pool
->ctx
, "Found '%s' at position %jd\n", string
, (intmax_t)offset
);
300 return loc_stringpool_append(pool
, string
);
303 void loc_stringpool_dump(struct loc_stringpool
* pool
) {
306 while (offset
< pool
->length
) {
307 const char* string
= loc_stringpool_get(pool
, offset
);
311 printf("%jd (%zu): %s\n", (intmax_t)offset
, strlen(string
), string
);
314 offset
+= strlen(string
) + 1;
318 size_t loc_stringpool_write(struct loc_stringpool
* pool
, FILE* f
) {
319 size_t size
= loc_stringpool_get_size(pool
);
321 return fwrite(pool
->data
, sizeof(*pool
->data
), size
, f
);