summaryrefslogtreecommitdiffstats
path: root/diffindex.c
diff options
context:
space:
mode:
Diffstat (limited to 'diffindex.c')
-rw-r--r--diffindex.c227
1 files changed, 227 insertions, 0 deletions
diff --git a/diffindex.c b/diffindex.c
new file mode 100644
index 0000000..0bff9aa
--- /dev/null
+++ b/diffindex.c
@@ -0,0 +1,227 @@
+/* This file is part of "reprepro"
+ * Copyright (C) 2003,2004,2005,2007 Bernhard R. Link
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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 St, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+#include <config.h>
+
+#include <errno.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "error.h"
+#include "names.h"
+#include "chunks.h"
+#include "readtextfile.h"
+#include "checksums.h"
+#include "diffindex.h"
+
+
+void diffindex_free(struct diffindex *diffindex) {
+ int i;
+
+ if (diffindex == NULL)
+ return;
+ checksums_free(diffindex->destination);
+ for (i = 0 ; i < diffindex->patchcount ; i ++) {
+ checksums_free(diffindex->patches[i].frompackages);
+ free(diffindex->patches[i].name);
+ checksums_free(diffindex->patches[i].checksums);
+ }
+ free(diffindex);
+}
+
+static void parse_sha1line(const char *p, /*@out@*/struct hashes *hashes, /*@out@*/const char **rest) {
+ setzero(struct hashes, hashes);
+
+ hashes->hashes[cs_sha1sum].start = p;
+ while ((*p >= 'a' && *p <= 'f') || (*p >= 'A' && *p <= 'F')
+ || (*p >= '0' && *p <= '9'))
+ p++;
+ hashes->hashes[cs_sha1sum].len = p - hashes->hashes[cs_sha1sum].start;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ hashes->hashes[cs_length].start = p;
+ while (*p >= '0' && *p <= '9')
+ p++;
+ hashes->hashes[cs_length].len = p - hashes->hashes[cs_length].start;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ *rest = p;
+}
+
+static inline retvalue add_current(const char *diffindexfile, struct diffindex *n, const char *current) {
+ struct hashes hashes;
+ const char *p;
+ retvalue r;
+
+ parse_sha1line(current, &hashes, &p);
+ if (hashes.hashes[cs_sha1sum].len == 0
+ || hashes.hashes[cs_length].len == 0
+ || *p != '\0') {
+ r = RET_ERROR;
+ } else
+ r = checksums_initialize(&n->destination, hashes.hashes);
+ ASSERT_NOT_NOTHING(r);
+ if (RET_WAS_ERROR(r))
+ fprintf(stderr, "Error parsing SHA1-Current in '%s'!\n",
+ diffindexfile);
+ return r;
+}
+
+static inline retvalue add_patches(const char *diffindexfile, struct diffindex *n, const struct strlist *patches) {
+ int i;
+
+ assert (patches->count == n->patchcount);
+
+ for (i = 0 ; i < n->patchcount; i++) {
+ struct hashes hashes;
+ const char *patchname;
+ retvalue r;
+
+ parse_sha1line(patches->values[i], &hashes, &patchname);
+ if (hashes.hashes[cs_sha1sum].len == 0
+ || hashes.hashes[cs_length].len == 0
+ || *patchname == '\0') {
+ r = RET_ERROR;
+ } else
+ r = checksums_initialize(&n->patches[i].checksums,
+ hashes.hashes);
+ ASSERT_NOT_NOTHING(r);
+ if (RET_WAS_ERROR(r)) {
+ fprintf(stderr,
+"Error parsing SHA1-Patches line %d in '%s':!\n'%s'\n",
+ i, diffindexfile, patches->values[i]);
+ return r;
+ }
+ n->patches[i].name = strdup(patchname);
+ if (FAILEDTOALLOC(n))
+ return RET_ERROR_OOM;
+ }
+ return RET_OK;
+}
+
+static inline retvalue add_history(const char *diffindexfile, struct diffindex *n, const struct strlist *history) {
+ int i, j;
+
+ for (i = 0 ; i < history->count ; i++) {
+ struct hashes hashes;
+ const char *patchname;
+ struct checksums *checksums;
+ retvalue r;
+
+ parse_sha1line(history->values[i], &hashes, &patchname);
+ if (hashes.hashes[cs_sha1sum].len == 0
+ || hashes.hashes[cs_length].len == 0
+ || *patchname == '\0') {
+ r = RET_ERROR;
+ } else
+ r = checksums_initialize(&checksums,
+ hashes.hashes);
+ ASSERT_NOT_NOTHING(r);
+ if (RET_WAS_ERROR(r)) {
+ fprintf(stderr,
+"Error parsing SHA1-History line %d in '%s':!\n'%s'\n",
+ i, diffindexfile, history->values[i]);
+ return r;
+ }
+ j = 0;
+ while (j < n->patchcount && strcmp(n->patches[j].name,
+ patchname) != 0)
+ j++;
+ if (j >= n->patchcount) {
+ fprintf(stderr,
+"'%s' lists '%s' in history but not in patches!\n",
+ diffindexfile, patchname);
+ checksums_free(checksums);
+ continue;
+ }
+ if (n->patches[j].frompackages != NULL) {
+ fprintf(stderr,
+"Warning: '%s' lists multiple histories for '%s'!\nOnly using last one!\n",
+ diffindexfile, patchname);
+ checksums_free(n->patches[j].frompackages);
+ }
+ n->patches[j].frompackages = checksums;
+ }
+ return RET_OK;
+}
+
+retvalue diffindex_read(const char *diffindexfile, struct diffindex **out_p) {
+ retvalue r;
+ char *chunk, *current;
+ struct strlist history, patches;
+ struct diffindex *n;
+
+ r = readtextfile(diffindexfile, diffindexfile, &chunk, NULL);
+ ASSERT_NOT_NOTHING(r);
+ if (RET_WAS_ERROR(r))
+ return r;
+ r = chunk_getextralinelist(chunk, "SHA1-History", &history);
+ if (r == RET_NOTHING) {
+ fprintf(stderr, "'%s' misses SHA1-History field\n",
+ diffindexfile);
+ r = RET_ERROR;
+ }
+ if (RET_WAS_ERROR(r)) {
+ free(chunk);
+ return r;
+ }
+ r = chunk_getextralinelist(chunk, "SHA1-Patches", &patches);
+ if (r == RET_NOTHING) {
+ fprintf(stderr, "'%s' misses SHA1-Patches field\n",
+ diffindexfile);
+ r = RET_ERROR;
+ }
+ if (RET_WAS_ERROR(r)) {
+ free(chunk);
+ strlist_done(&history);
+ return r;
+ }
+ r = chunk_getvalue(chunk, "SHA1-Current", &current);
+ free(chunk);
+ if (r == RET_NOTHING) {
+ fprintf(stderr, "'%s' misses SHA1-Current field\n",
+ diffindexfile);
+ r = RET_ERROR;
+ }
+ if (RET_WAS_ERROR(r)) {
+ strlist_done(&history);
+ strlist_done(&patches);
+ return r;
+ }
+ n = calloc(1, sizeof(struct diffindex) +
+ patches.count * sizeof(struct diffindex_patch));
+ if (FAILEDTOALLOC(n)) {
+ strlist_done(&history);
+ strlist_done(&patches);
+ free(current);
+ return r;
+ }
+ n->patchcount = patches.count;
+ r = add_current(diffindexfile, n, current);
+ if (RET_IS_OK(r))
+ r = add_patches(diffindexfile, n, &patches);
+ if (RET_IS_OK(r))
+ r = add_history(diffindexfile, n, &history);
+ ASSERT_NOT_NOTHING(r);
+ strlist_done(&history);
+ strlist_done(&patches);
+ free(current);
+ if (RET_IS_OK(r))
+ *out_p = n;
+ else
+ diffindex_free(n);
+ return r;
+}