--- /dev/null
+/*
+ * Copyright (C) 2014 J. Ali Harlow <ali@juiblex.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "razor.h"
+#include "razor-internal.h"
+
+static size_t
+dump_raw(FILE *fp, void *raw, char *what, size_t length, size_t offset)
+{
+ size_t i, n = 0;
+ unsigned char *bytes = raw;
+
+ while (length) {
+ fprintf(fp, "%05lX %s", (unsigned long)(offset + n), what);
+ for (i = 0; (i < 16) && (length > 0);) {
+ if (length >= 4) {
+ fprintf(fp, " %08X", *(uint32_t *)bytes);
+ bytes += 4;
+ n += 4;
+ length -= 4;
+ i += 4;
+ } else if (length >= 2) {
+ fprintf(fp, " %04X", *(unsigned short *)bytes);
+ bytes += 2;
+ n += 2;
+ length -= 2;
+ i += 2;
+ } else {
+ fprintf(fp, " %02X", *bytes);
+ bytes++;
+ n++;
+ length--;
+ i++;
+ }
+ }
+ fprintf(fp, "\n");
+ }
+
+ return n;
+}
+
+static size_t
+dump_string(FILE *fp, char *pool, size_t length, size_t offset)
+{
+ size_t n = 0;
+ unsigned char c;
+
+ fprintf(fp, "\"");
+ while (offset + n < length) {
+ c = pool[offset + n++];
+ if (c == '\0') {
+ fprintf(fp, "\\0");
+ break;
+ }
+ else if (c == '\\' || c == '"')
+ fprintf(fp, "\\%c", c);
+ else if (c >= ' ' && c <= '~')
+ fprintf(fp, "%c", c);
+ else
+ fprintf(fp, "\\x%02X", c);
+ }
+ fprintf(fp, "\"");
+
+ return n;
+}
+
+static size_t
+dump_pool(FILE *fp, char *pool, char *what, size_t length, size_t offset)
+{
+ size_t n = 0;
+
+ fprintf(fp, "%05lX %s {\n", (unsigned long)offset, what);
+
+ while (n < length) {
+ fprintf(fp, " %08X ", (uint32_t)n);
+ n += dump_string(fp, pool, length, n);
+ fprintf(fp, "\n");
+ }
+
+ fprintf(fp, "}\n");
+
+ return n;
+}
+
+static size_t
+dump_header(FILE *fp, struct razor_set_header *header, size_t length,
+ size_t offset)
+{
+ if (length >= sizeof(*header)) {
+ fprintf(fp, "%05lX header ", (unsigned long)offset);
+ fprintf(fp, "{ magic=%08X version=%08X num_sections=%08X }\n",
+ header->magic, header->version, header->num_sections);
+ return sizeof(*header);
+ } else
+ return dump_raw(fp, header, "unknown", length, offset);
+}
+
+static size_t
+dump_section(FILE *fp, struct razor_set_section *section, size_t length,
+ size_t offset, int indx)
+{
+ if (length >= sizeof(*section)) {
+ fprintf(fp, "%05lX section %X ", (unsigned long)offset, indx);
+ fprintf(fp, "{ name=%08X offset=%08X size=%08X }\n",
+ section->name, section->offset, section->size);
+ return sizeof(*section);
+ } else
+ return dump_raw(fp, section, "unknown", length, offset);
+}
+
+static void
+dump_list_head(FILE *fp, struct list_head *head)
+{
+ fprintf(fp, "{ list_ptr=%06X flags=%02X ",
+ head->list_ptr, head->flags);
+ if (head->flags == RAZOR_EMPTY_LIST)
+ fprintf(fp, "(EMPTY_LIST) ");
+ else if (head->flags == RAZOR_IMMEDIATE)
+ fprintf(fp, "(IMMEDIATE) ");
+ fprintf(fp,"}");
+}
+
+static void
+dump_list_link(FILE *fp, struct list *list)
+{
+ fprintf(fp, "{ data=%06X flags=%02X ",
+ list->data, list->flags);
+ if (list->flags == RAZOR_ENTRY_LAST)
+ fprintf(fp, "(ENTRY_LAST) ");
+ else if (list->flags == RAZOR_ENTRY_FIRST)
+ fprintf(fp, "(ENTRY_FIRST) ");
+ fprintf(fp,"}");
+}
+
+static void
+expand_pooled_string(FILE *fp, struct array *pool, uint32_t str)
+{
+ if (pool->data && str < pool->size) {
+ fprintf(fp, "(");
+ dump_string(fp, pool->data, pool->size, str);
+ fprintf(fp, ") ");
+ }
+}
+
+static size_t
+dump_package(FILE *fp, struct razor_package *package, size_t length,
+ size_t offset, struct array *string_pool, int indx)
+{
+ if (length >= sizeof(*package)) {
+ fprintf(fp, " %05lX package %X ", (unsigned long)offset,
+ indx);
+ fprintf(fp, "{ name=%06X ", package->name);
+ expand_pooled_string(fp, string_pool, package->name);
+ fprintf(fp, "flags=%02X\n version=%08X ",
+ package->flags, package->version);
+ expand_pooled_string(fp, string_pool, package->version);
+ fprintf(fp, "arch=%08X ", package->arch);
+ expand_pooled_string(fp, string_pool, package->arch);
+ fprintf(fp, "\n "
+ "summary=%08X description=%08X url=%08X license=%08X\n",
+ package->summary, package->description,
+ package->url, package->license);
+ fprintf(fp," properties=");
+ dump_list_head(fp, &package->properties);
+ fprintf(fp,"\n");
+ fprintf(fp," files=");
+ dump_list_head(fp, &package->files);
+ fprintf(fp,"\n");
+ fprintf(fp," install_prefixes=");
+ dump_list_head(fp, &package->install_prefixes);
+ fprintf(fp,"\n");
+ fprintf(fp," preun={ program=%08X body=%08X }\n",
+ package->preun.program, package->preun.body);
+ fprintf(fp," postun={ program=%08X body=%08X }\n",
+ package->postun.program, package->postun.body);
+ fprintf(fp," }\n");
+ return sizeof(*package);
+ } else
+ return dump_raw(fp, package, "unknown", length, offset);
+}
+
+static size_t
+dump_packages(FILE *fp, struct razor_package *packages, size_t length,
+ size_t offset, struct array *string_pool)
+{
+ size_t n = 0;
+ int i = 0;
+
+ fprintf(fp, "%05lX packages {\n", (unsigned long)offset);
+
+ while (n < length) {
+ n += dump_package(fp, packages, length - n, n, string_pool, i);
+ packages++;
+ i++;
+ }
+
+ fprintf(fp, "}\n");
+
+ return n;
+}
+
+static size_t
+dump_property(FILE *fp, struct razor_property *property, size_t length,
+ size_t offset, struct array *string_pool)
+{
+ if (length >= sizeof(*property)) {
+ fprintf(fp, " %05lX property ", (unsigned long)offset);
+ fprintf(fp, "{ name=%08X ", property->name);
+ expand_pooled_string(fp, string_pool, property->name);
+ fprintf(fp, "\n flags=%08X (", property->flags);
+ if (property->flags & RAZOR_PROPERTY_LESS)
+ fprintf(fp, "<");
+ if (property->flags & RAZOR_PROPERTY_GREATER)
+ fprintf(fp, ">");
+ if (property->flags & RAZOR_PROPERTY_EQUAL)
+ fprintf(fp, "=");
+ switch (property->flags & RAZOR_PROPERTY_TYPE_MASK) {
+ case RAZOR_PROPERTY_REQUIRES:
+ fprintf(fp, " requires");
+ break;
+ case RAZOR_PROPERTY_PROVIDES:
+ fprintf(fp, " provides");
+ break;
+ case RAZOR_PROPERTY_CONFLICTS:
+ fprintf(fp, " conflicts");
+ break;
+ case RAZOR_PROPERTY_OBSOLETES:
+ fprintf(fp, " obsoletes");
+ break;
+ }
+ if (property->flags & RAZOR_PROPERTY_PRE)
+ fprintf(fp, " pre");
+ if (property->flags & RAZOR_PROPERTY_POST)
+ fprintf(fp, " post");
+ if (property->flags & RAZOR_PROPERTY_PREUN)
+ fprintf(fp, " preun");
+ if (property->flags & RAZOR_PROPERTY_POSTUN)
+ fprintf(fp, " postun");
+ fprintf(fp, ") version=%08X ", property->version);
+ expand_pooled_string(fp, string_pool, property->version);
+ fprintf(fp,"\n packages=");
+ dump_list_head(fp, &property->packages);
+ fprintf(fp,"\n");
+ fprintf(fp," }\n");
+ return sizeof(*property);
+ } else
+ return dump_raw(fp, property, "unknown", length, offset);
+}
+
+static size_t
+dump_properties(FILE *fp, struct razor_property *properties, size_t length,
+ size_t offset, struct array *string_pool)
+{
+ size_t n = 0;
+
+ fprintf(fp, "%05lX properties {\n", (unsigned long)offset);
+
+ while (n < length) {
+ n += dump_property(fp, properties, length - n, n, string_pool);
+ properties++;
+ }
+
+ fprintf(fp, "}\n");
+
+ return n;
+}
+
+static size_t
+dump_entry(FILE *fp, struct razor_entry *entry, size_t length, size_t offset,
+ struct array *string_pool, int indx)
+{
+ if (length >= sizeof(*entry)) {
+ fprintf(fp, " %05lX entry %X ", (unsigned long)offset, indx);
+ fprintf(fp, "{ name=%06X ", entry->name);
+ expand_pooled_string(fp, string_pool, entry->name);
+ fprintf(fp, "\n flags=%02X ", entry->flags);
+ if (entry->flags == RAZOR_ENTRY_LAST)
+ fprintf(fp, "(LAST) ");
+ fprintf(fp, "start=%08X", entry->start);
+ if (!entry->start)
+ fprintf(fp, " (NONE)");
+ fprintf(fp,"\n packages=");
+ dump_list_head(fp, &entry->packages);
+ fprintf(fp,"\n");
+ fprintf(fp," }\n");
+ return sizeof(*entry);
+ } else
+ return dump_raw(fp, entry, "unknown", length, offset);
+}
+
+static size_t
+dump_files(FILE *fp, struct razor_entry *entries, size_t length, size_t offset,
+ struct array *string_pool)
+{
+ size_t n = 0;
+ int i = 0;
+
+ fprintf(fp, "%05lX files {\n", (unsigned long)offset);
+
+ while (n < length) {
+ n += dump_entry(fp, entries, length - n, n, string_pool, i);
+ i++;
+ entries++;
+ }
+
+ fprintf(fp, "}\n");
+
+ return n;
+}
+
+static size_t
+dump_lists(FILE *fp, struct list *lists, char *what, size_t length,
+ size_t offset)
+{
+ int i = 0;
+ size_t n = 0;
+
+ fprintf(fp, "%05lX %s {\n", (unsigned long)offset, what);
+
+ while (n + sizeof(*lists) <= length) {
+ fprintf(fp, " list %06X ", i);
+ dump_list_link(fp, lists);
+ fprintf(fp, "\n");
+ n += sizeof(*lists);
+ lists++;
+ i++;
+ }
+
+ if (length - n)
+ n += dump_raw(fp, lists, "unknown", length - n, offset + n);
+
+ fprintf(fp, "}\n");
+
+ return n;
+}
+
+RAZOR_EXPORT int
+razor_dump_database(FILE *fp, const char *root, const char *filename,
+ struct razor_error **error)
+{
+ int i;
+ char *s, *path, *data;
+ struct array pool = { 0, };
+ struct array string_pool = { 0, };
+ struct array file_string_pool = { 0, };
+ struct array details_string_pool = { 0, };
+ unsigned char *contents;
+ size_t length, len, n, min_offset;
+ struct razor_set_header *header;
+ struct razor_set_section *section, *sections;
+ struct razor_package *package;
+ struct razor_property *prop;
+ struct razor_entry *entry;
+ struct list *list;
+
+ if (!filename)
+ filename = "system.rzdb";
+
+ s = razor_concat(razor_get_database_path(), "/", filename, NULL);
+ path = razor_path_add_root(s, root);
+ free(s);
+ contents = razor_file_get_contents(path, &length, 0, error);
+ free(path);
+
+ if (!contents)
+ return -1;
+
+ n = 0;
+
+ header = (void *)contents;
+
+ if (length - n)
+ n += dump_header(fp, header, length - n, n);
+
+ min_offset = length;
+ sections = (void *)(contents + n);
+ for (i = 0; i < header->num_sections; i++) {
+ if (n == length)
+ break;
+ section = (void *)(contents + n);
+ if (section->offset < min_offset)
+ min_offset = section->offset;
+ n += dump_section(fp, section, length - n, n, i);
+ }
+
+ if (length - n) {
+ pool.data = (char *)(contents + n);
+ pool.size = min_offset - n;
+ n += dump_pool(fp, pool.data, "pool", pool.size, n);
+ }
+
+ if ((length - n) && PADDING(n, 4))
+ n += dump_raw(fp, contents + n, "padding", PADDING(n, 4), n);
+
+ for (i = 0; length - n && i < header->num_sections; i++) {
+ if (sections[i].name < pool.size &&
+ ((char *)pool.data)[pool.size - 1] == '\0')
+ s = pool.data + sections[i].name;
+ else
+ continue;
+
+ data = (char *)(contents + sections[i].offset);
+
+ if (!strcmp(s, "string_pool")) {
+ string_pool.data = data;
+ string_pool.size = sections[i].size;
+ } else if (!strcmp(s, "file_string_pool")) {
+ file_string_pool.data = data;
+ file_string_pool.size = sections[i].size;
+ } else if (!strcmp(s, "details_string_pool")) {
+ details_string_pool.data = data;
+ details_string_pool.size = sections[i].size;
+ }
+ }
+
+ for (i = 0; i < header->num_sections; i++) {
+ if (n == length)
+ break;
+ section = sections + i;
+ if (section->offset != n)
+ continue;
+ len = section->size;
+ if (len > length - n)
+ len = length - n;
+
+ if (section->name < pool.size &&
+ ((char *)pool.data)[pool.size - 1] == '\0')
+ s = pool.data + section->name;
+ else
+ s = "unknown";
+
+ if (!strcmp(s, "string_pool") ||
+ !strcmp(s, "file_string_pool") ||
+ !strcmp(s, "details_string_pool"))
+ n += dump_pool(fp, (char *)(contents + n), s, len, n);
+ else if (!strcmp(s, "packages")) {
+ package = (void *)(contents + n);
+ n += dump_packages(fp, package, len, n, &string_pool);
+ } else if (!strcmp(s, "properties")) {
+ prop = (void *)(contents + n);
+ n += dump_properties(fp, prop, len, n, &string_pool);
+ } else if (!strcmp(s, "files")) {
+ entry = (void *)(contents + n);
+ n += dump_files(fp, entry, len, n, &file_string_pool);
+ } else if (!strcmp(s, "package_pool") ||
+ !strcmp(s, "property_pool") ||
+ !strcmp(s, "prefix_pool") ||
+ !strcmp(s, "file_pool")) {
+ list = (void *)(contents + n);
+ n += dump_lists(fp, list, s, len, n);
+ } else
+ n += dump_raw(fp, contents + n, s, len, n);
+
+ if ((length - n) && PADDING(n, 4))
+ n += dump_raw(fp, contents + n, "padding",
+ PADDING(n, 4), n);
+ }
+
+ if (length - n)
+ n += dump_raw(fp, contents + n, "unknown", length - n, n);
+
+ fprintf(fp, "%05lX EOF\n", (unsigned long)n);
+
+ razor_file_free_contents(contents, length);
+
+ return 0;
+}