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.
17 #include <arpa/inet.h>
24 #include <sys/types.h>
26 #include <loc/libloc.h>
28 #include "libloc-private.h"
30 #include "stringpool.h"
40 struct loc_stringpool
* pool
;
43 const char* LOC_DATABASE_MAGIC
= "LOCDBXX";
44 unsigned int LOC_DATABASE_VERSION
= 0;
46 struct loc_database_magic
{
49 // Database version information
53 struct loc_database_header_v0
{
54 // Vendor who created the database
57 // Description of the database
60 // Tells us where the pool starts
65 LOC_EXPORT
int loc_database_new(struct loc_ctx
* ctx
, struct loc_database
** database
, size_t pool_size
) {
66 struct loc_database
* db
= calloc(1, sizeof(*db
));
71 db
->ctx
= loc_ref(ctx
);
74 DEBUG(db
->ctx
, "Database allocated at %p\n", db
);
77 int r
= loc_stringpool_new(db
->ctx
, &db
->pool
, pool_size
);
79 loc_database_unref(db
);
88 LOC_EXPORT
int loc_database_open(struct loc_ctx
* ctx
, struct loc_database
** database
, FILE* f
) {
89 int r
= loc_database_new(ctx
, database
, 0);
93 return loc_database_read(*database
, f
);
96 LOC_EXPORT
struct loc_database
* loc_database_ref(struct loc_database
* db
) {
102 static void loc_database_free(struct loc_database
* db
) {
103 DEBUG(db
->ctx
, "Releasing database %p\n", db
);
105 loc_stringpool_unref(db
->pool
);
111 LOC_EXPORT
struct loc_database
* loc_database_unref(struct loc_database
* db
) {
112 if (--db
->refcount
> 0)
115 loc_database_free(db
);
119 LOC_EXPORT
const char* loc_database_get_vendor(struct loc_database
* db
) {
120 return loc_stringpool_get(db
->pool
, db
->vendor
);
123 LOC_EXPORT
int loc_database_set_vendor(struct loc_database
* db
, const char* vendor
) {
124 // Add the string to the string pool
125 off_t offset
= loc_stringpool_add(db
->pool
, vendor
);
133 LOC_EXPORT
const char* loc_database_get_description(struct loc_database
* db
) {
134 return loc_stringpool_get(db
->pool
, db
->description
);
137 LOC_EXPORT
int loc_database_set_description(struct loc_database
* db
, const char* description
) {
138 // Add the string to the string pool
139 off_t offset
= loc_stringpool_add(db
->pool
, description
);
143 db
->description
= offset
;
147 static int loc_database_read_magic(struct loc_database
* db
, FILE* f
) {
148 struct loc_database_magic magic
;
151 size_t bytes_read
= fread(&magic
, 1, sizeof(magic
), f
);
153 // Check if we have been able to read enough data
154 if (bytes_read
< sizeof(magic
)) {
155 ERROR(db
->ctx
, "Could not read enough data to validate magic bytes\n");
156 DEBUG(db
->ctx
, "Read %zu bytes, but needed %zu\n", bytes_read
, sizeof(magic
));
160 // Compare magic bytes
161 if (memcmp(LOC_DATABASE_MAGIC
, magic
.magic
, strlen(LOC_DATABASE_MAGIC
)) == 0) {
162 DEBUG(db
->ctx
, "Magic value matches\n");
165 db
->version
= ntohs(magic
.version
);
166 DEBUG(db
->ctx
, "Database version is %u\n", db
->version
);
171 ERROR(db
->ctx
, "Database format is not compatible\n");
177 static int loc_database_read_header_v0(struct loc_database
* db
, FILE* f
) {
178 struct loc_database_header_v0 header
;
181 size_t size
= fread(&header
, 1, sizeof(header
), f
);
183 if (size
< sizeof(header
)) {
184 ERROR(db
->ctx
, "Could not read enough data for header\n");
189 db
->vendor
= ntohl(header
.vendor
);
190 db
->description
= ntohl(header
.description
);
193 off_t pool_offset
= ntohl(header
.pool_offset
);
194 size_t pool_length
= ntohl(header
.pool_length
);
196 int r
= loc_stringpool_read(db
->pool
, f
, pool_offset
, pool_length
);
203 static int loc_database_read_header(struct loc_database
* db
, FILE* f
) {
204 switch (db
->version
) {
206 return loc_database_read_header_v0(db
, f
);
209 ERROR(db
->ctx
, "Incompatible database version: %u\n", db
->version
);
214 LOC_EXPORT
int loc_database_read(struct loc_database
* db
, FILE* f
) {
215 int r
= fseek(f
, 0, SEEK_SET
);
220 r
= loc_database_read_magic(db
, f
);
225 r
= loc_database_read_header(db
, f
);
232 static void loc_database_make_magic(struct loc_database
* db
, struct loc_database_magic
* magic
) {
234 for (unsigned int i
= 0; i
< strlen(LOC_DATABASE_MAGIC
); i
++)
235 magic
->magic
[i
] = LOC_DATABASE_MAGIC
[i
];
238 magic
->version
= htons(LOC_DATABASE_VERSION
);
241 LOC_EXPORT
int loc_database_write(struct loc_database
* db
, FILE* f
) {
242 struct loc_database_magic magic
;
243 loc_database_make_magic(db
, &magic
);
246 struct loc_database_header_v0 header
;
247 header
.vendor
= htonl(db
->vendor
);
248 header
.description
= htonl(db
->description
);
253 // Start writing at the beginning of the file
254 r
= fseek(f
, 0, SEEK_SET
);
259 offset
+= fwrite(&magic
, 1, sizeof(magic
), f
);
261 // Skip the space we need to write the header later
262 r
= fseek(f
, sizeof(header
), SEEK_CUR
);
264 DEBUG(db
->ctx
, "Could not seek to position after header\n");
267 offset
+= sizeof(header
);
269 // Save the offset of the pool section
270 DEBUG(db
->ctx
, "Pool starts at %jd bytes\n", offset
);
271 header
.pool_offset
= htonl(offset
);
274 size_t pool_length
= loc_stringpool_write(db
->pool
, f
);
275 DEBUG(db
->ctx
, "Pool has a length of %zu bytes\n", pool_length
);
276 header
.pool_length
= htonl(pool_length
);
279 r
= fseek(f
, sizeof(magic
), SEEK_SET
);
283 offset
+= fwrite(&header
, 1, sizeof(header
), f
);