X-Git-Url: http://git.ipfire.org/?p=people%2Fms%2Flibloc.git;a=blobdiff_plain;f=src%2Fdatabase.c;h=9db875b87012e7e6327757b0ffb39006f42850ca;hp=345b4f7ec272c5b80f811be188b2987369194fde;hb=5df10c90415a660d463764b1c7a757f3275f4043;hpb=8eb67d2641d5b184bb7c955ff55dc892f2f7f3e7 diff --git a/src/database.c b/src/database.c index 345b4f7..9db875b 100644 --- a/src/database.c +++ b/src/database.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include #include @@ -35,7 +37,9 @@ struct loc_database { struct loc_ctx* ctx; int refcount; + FILE* file; unsigned int version; + time_t created_at; off_t vendor; off_t description; @@ -55,6 +59,9 @@ LOC_EXPORT int loc_database_new(struct loc_ctx* ctx, struct loc_database** datab db->ctx = loc_ref(ctx); db->refcount = 1; + // Save creation time + db->created_at = time(NULL); + DEBUG(db->ctx, "Database allocated at %p\n", db); // Create string pool @@ -96,6 +103,10 @@ static void loc_database_free(struct loc_database* db) { loc_stringpool_unref(db->pool); + // Close file + if (db->file) + fclose(db->file); + loc_unref(db->ctx); free(db); } @@ -108,6 +119,10 @@ LOC_EXPORT struct loc_database* loc_database_unref(struct loc_database* db) { return NULL; } +LOC_EXPORT time_t loc_database_created_at(struct loc_database* db) { + return db->created_at; +} + LOC_EXPORT const char* loc_database_get_vendor(struct loc_database* db) { return loc_stringpool_get(db->pool, db->vendor); } @@ -192,11 +207,11 @@ LOC_EXPORT struct loc_as* loc_database_add_as(struct loc_database* db, uint32_t return __loc_database_add_as(db, as); } -static int loc_database_read_magic(struct loc_database* db, FILE* f) { +static int loc_database_read_magic(struct loc_database* db) { struct loc_database_magic magic; // Read from file - size_t bytes_read = fread(&magic, 1, sizeof(magic), f); + size_t bytes_read = fread(&magic, 1, sizeof(magic), db->file); // Check if we have been able to read enough data if (bytes_read < sizeof(magic)) { @@ -223,18 +238,18 @@ static int loc_database_read_magic(struct loc_database* db, FILE* f) { } static int loc_database_read_as_section_v0(struct loc_database* db, - off_t as_offset, size_t as_length, FILE* f) { + off_t as_offset, size_t as_length) { struct loc_database_as_v0 dbobj; // Read from the start of the section - int r = fseek(f, as_offset, SEEK_SET); + int r = fseek(db->file, as_offset, SEEK_SET); if (r) return r; // Read all ASes size_t as_count = as_length / sizeof(dbobj); for (unsigned int i = 0; i < as_count; i++) { - size_t bytes_read = fread(&dbobj, 1, sizeof(dbobj), f); + size_t bytes_read = fread(&dbobj, 1, sizeof(dbobj), db->file); if (bytes_read < sizeof(dbobj)) { ERROR(db->ctx, "Could not read an AS object\n"); return -ENOMSG; @@ -256,11 +271,11 @@ static int loc_database_read_as_section_v0(struct loc_database* db, return 0; } -static int loc_database_read_header_v0(struct loc_database* db, FILE* f) { +static int loc_database_read_header_v0(struct loc_database* db) { struct loc_database_header_v0 header; // Read from file - size_t size = fread(&header, 1, sizeof(header), f); + size_t size = fread(&header, 1, sizeof(header), db->file); if (size < sizeof(header)) { ERROR(db->ctx, "Could not read enough data for header\n"); @@ -268,6 +283,7 @@ static int loc_database_read_header_v0(struct loc_database* db, FILE* f) { } // Copy over data + db->created_at = be64toh(header.created_at); db->vendor = ntohl(header.vendor); db->description = ntohl(header.description); @@ -275,7 +291,7 @@ static int loc_database_read_header_v0(struct loc_database* db, FILE* f) { off_t pool_offset = ntohl(header.pool_offset); size_t pool_length = ntohl(header.pool_length); - int r = loc_stringpool_read(db->pool, f, pool_offset, pool_length); + int r = loc_stringpool_read(db->pool, db->file, pool_offset, pool_length); if (r) return r; @@ -283,17 +299,17 @@ static int loc_database_read_header_v0(struct loc_database* db, FILE* f) { off_t as_offset = ntohl(header.as_offset); size_t as_length = ntohl(header.as_length); - r = loc_database_read_as_section_v0(db, as_offset, as_length, f); + r = loc_database_read_as_section_v0(db, as_offset, as_length); if (r) return r; return 0; } -static int loc_database_read_header(struct loc_database* db, FILE* f) { +static int loc_database_read_header(struct loc_database* db) { switch (db->version) { case 0: - return loc_database_read_header_v0(db, f); + return loc_database_read_header_v0(db); default: ERROR(db->ctx, "Incompatible database version: %u\n", db->version); @@ -302,17 +318,29 @@ static int loc_database_read_header(struct loc_database* db, FILE* f) { } LOC_EXPORT int loc_database_read(struct loc_database* db, FILE* f) { - int r = fseek(f, 0, SEEK_SET); + // Copy the file pointer and work on that so we don't care if + // the calling function closes the file + int fd = fileno(f); + + // Make a copy + fd = dup(fd); + + // Retrieve a file pointer + db->file = fdopen(fd, "r"); + if (!db->file) + return -errno; + + int r = fseek(db->file, 0, SEEK_SET); if (r) return r; // Read magic bytes - r = loc_database_read_magic(db, f); + r = loc_database_read_magic(db); if (r) return r; // Read the header - r = loc_database_read_header(db, f); + r = loc_database_read_header(db); if (r) return r; @@ -328,12 +356,57 @@ static void loc_database_make_magic(struct loc_database* db, struct loc_database magic->version = htons(LOC_DATABASE_VERSION); } +static void loc_database_align_page_boundary(off_t* offset, FILE* f) { + // Move to next page boundary + while (*offset % LOC_DATABASE_PAGE_SIZE > 0) + *offset += fwrite("", 1, 1, f); +} + +static int loc_database_write_pool(struct loc_database* db, struct loc_database_header_v0* header, off_t* offset, FILE* f) { + // Save the offset of the pool section + DEBUG(db->ctx, "Pool starts at %jd bytes\n", *offset); + header->pool_offset = htonl(*offset); + + // Write the pool + size_t pool_length = loc_stringpool_write(db->pool, f); + *offset += pool_length; + + DEBUG(db->ctx, "Pool has a length of %zu bytes\n", pool_length); + header->pool_length = htonl(pool_length); + + return 0; +} + +static int loc_database_write_as_section(struct loc_database* db, + struct loc_database_header_v0* header, off_t* offset, FILE* f) { + DEBUG(db->ctx, "AS section starts at %jd bytes\n", *offset); + header->as_offset = htonl(*offset); + + size_t as_length = 0; + + struct loc_database_as_v0 dbas; + for (unsigned int i = 0; i < db->as_count; i++) { + // Convert AS into database format + loc_as_to_database_v0(db->as[i], &dbas); + + // Write to disk + offset += fwrite(&dbas, 1, sizeof(dbas), f); + as_length += sizeof(dbas); + } + + DEBUG(db->ctx, "AS section has a length of %zu bytes\n", as_length); + header->as_length = htonl(as_length); + + return 0; +} + LOC_EXPORT int loc_database_write(struct loc_database* db, FILE* f) { struct loc_database_magic magic; loc_database_make_magic(db, &magic); // Make the header struct loc_database_header_v0 header; + header.created_at = htobe64(db->created_at); header.vendor = htonl(db->vendor); header.description = htonl(db->description); @@ -356,27 +429,19 @@ LOC_EXPORT int loc_database_write(struct loc_database* db, FILE* f) { } offset += sizeof(header); - // Write all ASes - header.as_offset = htonl(offset); + loc_database_align_page_boundary(&offset, f); - struct loc_database_as_v0 dbas; - for (unsigned int i = 0; i < db->as_count; i++) { - // Convert AS into database format - loc_as_to_database_v0(db->as[i], &dbas); - - // Write to disk - offset += fwrite(&dbas, 1, sizeof(dbas), f); - } - header.as_length = htonl(db->as_count * sizeof(dbas)); + // Write all ASes + r = loc_database_write_as_section(db, &header, &offset, f); + if (r) + return r; - // Save the offset of the pool section - DEBUG(db->ctx, "Pool starts at %jd bytes\n", offset); - header.pool_offset = htonl(offset); + loc_database_align_page_boundary(&offset, f); - // Size of the pool - size_t pool_length = loc_stringpool_write(db->pool, f); - DEBUG(db->ctx, "Pool has a length of %zu bytes\n", pool_length); - header.pool_length = htonl(pool_length); + // Write pool + r = loc_database_write_pool(db, &header, &offset, f); + if (r) + return r; // Write the header r = fseek(f, sizeof(magic), SEEK_SET);