static gboolean _read_header(SerializeArchive *sa, NVTable **nvtable) { g_assert(*nvtable == NULL); NVTable *res = (NVTable *)g_malloc(sizeof(NVTable)); if (!serialize_read_uint32(sa, &res->size)) { goto error; } if (!serialize_read_uint32(sa, &res->used)) { goto error; } if (!serialize_read_uint16(sa, &res->num_dyn_entries)) { goto error; } if (!serialize_read_uint8(sa, &res->num_static_entries)) { goto error; } res = (NVTable *)g_realloc(res, res->size); res->borrowed = FALSE; res->ref_cnt = 1; *nvtable = res; return TRUE; error: if (res) g_free(res); return FALSE; }
static gboolean _read_header(SerializeArchive *sa, NVTable **nvtable) { NVTable *res = NULL; guint32 size; g_assert(*nvtable == NULL); if (!serialize_read_uint32(sa, &size)) goto error; if (size > NV_TABLE_MAX_BYTES) goto error; res = (NVTable *) g_malloc(size); res->size = size; if (!serialize_read_uint32(sa, &res->used)) goto error; if (!serialize_read_uint16(sa, &res->index_size)) goto error; if (!serialize_read_uint8(sa, &res->num_static_entries)) goto error; /* static entries has to be known by this syslog-ng, if they are over * LM_V_MAX, that means we have no clue how an entry is called, as static * entries don't contain names. If there are less static entries, that * can be ok. */ if (res->num_static_entries > LM_V_MAX) goto error; /* validates self->used and self->index_size value as compared to "size" */ if (!nv_table_alloc_check(res, 0)) goto error; res->borrowed = FALSE; res->ref_cnt = 1; *nvtable = res; return TRUE; error: if (res) g_free(res); return FALSE; }
static gboolean _read_log_stamp(SerializeArchive *sa, UnixTime *stamp) { guint64 val64; guint32 val; if (!serialize_read_uint64(sa, &val64)) return FALSE; stamp->ut_sec = (gint64) val64; if (!serialize_read_uint32(sa, &val)) return FALSE; stamp->ut_usec = val; if (!serialize_read_uint32(sa, &val)) return FALSE; stamp->ut_gmtoff = (gint) val; return TRUE; }
static gboolean _read_log_stamp(SerializeArchive *sa, LogStamp *stamp) { guint64 val64; guint32 val; if (!serialize_read_uint64(sa, &val64)) return FALSE; stamp->tv_sec = (gint64) val64; if (!serialize_read_uint32(sa, &val)) return FALSE; stamp->tv_usec = val; if (!serialize_read_uint32(sa, &val)) return FALSE; stamp->zone_offset = (gint) val; return TRUE; }
static gboolean _deserialize_static_entries(SerializeArchive *sa, NVTable *res) { guint32 i; for (i = 0; i < res->num_static_entries; i++) { if (!serialize_read_uint32(sa, &res->static_entries[i])) return FALSE; } return TRUE; }
static gboolean log_proto_buffered_server_convert_state(LogProtoBufferedServer *self, guint8 persist_version, gpointer old_state, gsize old_state_size, LogProtoBufferedServerState *state) { if (persist_version <= 2) { state->header.version = 0; state->file_inode = 0; state->raw_stream_pos = strtoll((gchar *) old_state, NULL, 10); state->file_size = 0; return TRUE; } else if (persist_version == 3) { SerializeArchive *archive; guint32 read_length; gint64 cur_size; gint64 cur_inode; gint64 cur_pos; guint16 version; gchar *buffer; gsize buffer_len; cur_inode = -1; cur_pos = 0; cur_size = 0; archive = serialize_buffer_archive_new(old_state, old_state_size); /* NOTE: the v23 conversion code adds an extra length field which we * need to read out. */ g_assert(serialize_read_uint32(archive, &read_length) && read_length == old_state_size - sizeof(read_length)); /* original v3 format starts here */ if (!serialize_read_uint16(archive, &version) || version != 0) { msg_error("Internal error restoring log reader state, stored data has incorrect version", evt_tag_int("version", version)); goto error_converting_v3; } if (!serialize_read_uint64(archive, (guint64 *) &cur_pos) || !serialize_read_uint64(archive, (guint64 *) &cur_inode) || !serialize_read_uint64(archive, (guint64 *) &cur_size)) { msg_error("Internal error restoring information about the current file position, restarting from the beginning"); goto error_converting_v3; } if (!serialize_read_uint16(archive, &version) || version != 0) { msg_error("Internal error, protocol state has incorrect version", evt_tag_int("version", version)); goto error_converting_v3; } if (!serialize_read_cstring(archive, &buffer, &buffer_len)) { msg_error("Internal error, error reading buffer contents", evt_tag_int("version", version)); goto error_converting_v3; } if (!self->buffer || state->buffer_size < buffer_len) { gsize buffer_size = MAX(self->super.options->init_buffer_size, buffer_len); self->buffer = g_realloc(self->buffer, buffer_size); } serialize_archive_free(archive); memcpy(self->buffer, buffer, buffer_len); state->buffer_pos = 0; state->pending_buffer_end = buffer_len; g_free(buffer); state->header.version = 0; state->file_inode = cur_inode; state->raw_stream_pos = cur_pos; state->file_size = cur_size; return TRUE; error_converting_v3: serialize_archive_free(archive); } return FALSE; }
static inline gboolean _read_magic(SerializeArchive *sa, guint32 *magic) { return serialize_read_uint32(sa, magic); }
static gboolean _deserialize_dyn_value(SerializeArchive *sa, NVDynValue* dyn_value) { return serialize_read_nvhandle(sa, &(dyn_value->handle)) && serialize_read_uint32(sa, &(dyn_value->ofs)); };
static gboolean _load_v4(PersistState *self, gboolean load_all_entries) { gint fd; gint64 file_size; gpointer map; gpointer key_block; guint32 key_size; PersistFileHeader *header; gint key_count, i; fd = open(self->commited_filename, O_RDONLY); if (fd < 0) { /* no previous data found */ return TRUE; } file_size = lseek(fd, 0, SEEK_END); if (file_size > ((1LL << 31) - 1)) { msg_error("Persistent file too large", evt_tag_str("filename", self->commited_filename), evt_tag_printf("size", "%" G_GINT64_FORMAT, file_size), NULL); return FALSE; } map = mmap(NULL, file_size, PROT_READ, MAP_SHARED, fd, 0); close(fd); if (map == MAP_FAILED) { msg_error("Error mapping persistent file into memory", evt_tag_str("filename", self->commited_filename), evt_tag_errno("error", errno), NULL); return FALSE; } header = (PersistFileHeader *) map; key_block = ((gchar *) map) + offsetof(PersistFileHeader, initial_key_store); key_size = sizeof((((PersistFileHeader *) NULL))->initial_key_store); key_count = GUINT32_FROM_BE(header->key_count); i = 0; while (i < key_count) { gchar *name; guint32 entry_ofs, chain_ofs; SerializeArchive *sa; sa = serialize_buffer_archive_new(key_block, key_size); while (i < key_count) { if (!serialize_read_cstring(sa, &name, NULL)) { serialize_archive_free(sa); msg_error("Persistent file format error, unable to fetch key name", NULL); goto free_and_exit; } if (name[0]) { if (serialize_read_uint32(sa, &entry_ofs)) { PersistValueHeader *value_header; i++; if (entry_ofs < sizeof(PersistFileHeader) || entry_ofs > file_size) { serialize_archive_free(sa); g_free(name); msg_error("Persistent file format error, entry offset is out of bounds", NULL); goto free_and_exit; } value_header = (PersistValueHeader *) ((gchar *) map + entry_ofs - sizeof(PersistValueHeader)); if ((value_header->in_use) || load_all_entries) { gpointer new_block; PersistEntryHandle new_handle; new_handle = _alloc_value(self, GUINT32_FROM_BE(value_header->size), FALSE, value_header->version); new_block = persist_state_map_entry(self, new_handle); memcpy(new_block, value_header + 1, GUINT32_FROM_BE(value_header->size)); persist_state_unmap_entry(self, new_handle); /* add key to the current file */ _add_key(self, name, new_handle); } g_free(name); } else { /* bad format */ serialize_archive_free(sa); g_free(name); msg_error("Persistent file format error, unable to fetch key name", NULL); goto free_and_exit; } } else { g_free(name); if (serialize_read_uint32(sa, &chain_ofs)) { /* end of block, chain to the next one */ if (chain_ofs == 0 || chain_ofs > file_size) { msg_error("Persistent file format error, key block chain offset is too large or zero", evt_tag_printf("key_block", "%08lx", (gulong) ((gchar *) key_block - (gchar *) map)), evt_tag_printf("key_size", "%d", key_size), evt_tag_int("ofs", chain_ofs), NULL); serialize_archive_free(sa); goto free_and_exit; } key_block = ((gchar *) map) + chain_ofs; key_size = GUINT32_FROM_BE(*(guint32 *) (((gchar *) key_block) - sizeof(PersistValueHeader))); if (chain_ofs + key_size > file_size) { msg_error("Persistent file format error, key block size is too large", evt_tag_int("key_size", key_size), NULL); serialize_archive_free(sa); goto free_and_exit; } break; } else { serialize_archive_free(sa); msg_error("Persistent file format error, unable to fetch chained key block offset", NULL); goto free_and_exit; } } } serialize_archive_free(sa); } free_and_exit: munmap(map, file_size); return TRUE; }