Skip to content

Commit 13f290d

Browse files
Zeno-soleclaude
andcommitted
feat: verify exported indices consistency after update/pull
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 55100ad commit 13f290d

3 files changed

Lines changed: 287 additions & 0 deletions

File tree

debian/changelog

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
reprepro (5.4.2-1deepin6) unstable; urgency=medium
2+
3+
* feat: verify exported indices consistency after update/pull
4+
5+
-- lichenggang <lichenggang@deepin.org> Tue, 14 Apr 2026 10:00:00 +0800
6+
17
reprepro (5.4.2-1deepin5) unstable; urgency=medium
28

39
* fix: import source file checksum error
Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
diff --git a/distribution.c b/distribution.c
2+
index 8b24365..62d8b60 100644
3+
--- a/distribution.c
4+
+++ b/distribution.c
5+
@@ -40,6 +40,8 @@
6+
#include "configparser.h"
7+
#include "byhandhook.h"
8+
#include "package.h"
9+
+#include "indexfile.h"
10+
+#include "filecntl.h"
11+
#include "distribution.h"
12+
13+
static retvalue distribution_free(struct distribution *distribution) {
14+
@@ -1074,6 +1076,216 @@ retvalue distribution_exportlist(enum exportwhen when, struct distribution *dist
15+
return result;
16+
}
17+
18+
+static int compare_string_pointers(const void *a, const void *b) {
19+
+ const char * const *sa = a;
20+
+ const char * const *sb = b;
21+
+ return strcmp(*sa, *sb);
22+
+}
23+
+
24+
+retvalue distribution_verify_exported_indices(struct distribution *distributions) {
25+
+ struct distribution *d;
26+
+ retvalue result = RET_OK;
27+
+
28+
+ for (d = distributions ; d != NULL ; d = d->next) {
29+
+ struct target *t;
30+
+
31+
+ if (d->omitted || !d->selected || !d->lookedat ||
32+
+ d->exportoptions[deo_noexport])
33+
+ continue;
34+
+
35+
+ for (t = d->targets ; t != NULL ; t = t->next) {
36+
+ struct package_cursor cursor;
37+
+ struct indexfile *idx = NULL;
38+
+ struct package pkg;
39+
+ struct strlist db_packages, idx_packages;
40+
+ char *basepath = NULL, *filepath = NULL, *indexpath = NULL;
41+
+ retvalue r;
42+
+ enum compression comp = c_none;
43+
+ int i, j;
44+
+ bool mismatch = false;
45+
+
46+
+ if (t->noexport)
47+
+ continue;
48+
+
49+
+ strlist_init(&db_packages);
50+
+ strlist_init(&idx_packages);
51+
+
52+
+ r = package_openiterator(t, READONLY, true, &cursor);
53+
+ if (RET_WAS_ERROR(r)) {
54+
+ RET_UPDATE(result, r);
55+
+ strlist_done(&db_packages);
56+
+ strlist_done(&idx_packages);
57+
+ continue;
58+
+ }
59+
+ while (package_next(&cursor)) {
60+
+ char *entry;
61+
+ r = package_getversion(&cursor.current);
62+
+ if (RET_WAS_ERROR(r)) {
63+
+ RET_UPDATE(result, r);
64+
+ mismatch = true;
65+
+ break;
66+
+ }
67+
+ entry = mprintf("%s|%s",
68+
+ cursor.current.name,
69+
+ cursor.current.version);
70+
+ if (FAILEDTOALLOC(entry)) {
71+
+ RET_UPDATE(result, RET_ERROR_OOM);
72+
+ mismatch = true;
73+
+ break;
74+
+ }
75+
+ r = strlist_add(&db_packages, entry);
76+
+ if (RET_WAS_ERROR(r)) {
77+
+ free(entry);
78+
+ RET_UPDATE(result, r);
79+
+ mismatch = true;
80+
+ break;
81+
+ }
82+
+ }
83+
+ r = package_closeiterator(&cursor);
84+
+ if (RET_WAS_ERROR(r)) {
85+
+ RET_UPDATE(result, r);
86+
+ strlist_done(&db_packages);
87+
+ strlist_done(&idx_packages);
88+
+ continue;
89+
+ }
90+
+ if (mismatch) {
91+
+ strlist_done(&db_packages);
92+
+ strlist_done(&idx_packages);
93+
+ continue;
94+
+ }
95+
+
96+
+ basepath = calc_dirconcat(global.distdir, d->codename);
97+
+ filepath = calc_dirconcat(basepath, t->relativedirectory);
98+
+ free(basepath);
99+
+ basepath = calc_dirconcat(filepath, t->exportmode->filename);
100+
+ free(filepath);
101+
+
102+
+ if (isregularfile(basepath)) {
103+
+ indexpath = basepath;
104+
+ basepath = NULL;
105+
+ comp = c_none;
106+
+ } else {
107+
+ indexpath = mprintf("%s.gz", basepath);
108+
+ if (!isregularfile(indexpath)) {
109+
+ if (db_packages.count > 0) {
110+
+ fprintf(stderr,
111+
+"Error: exported index file for %s not found (expected %s or %s.gz)!\n",
112+
+ t->identifier, basepath, basepath);
113+
+ RET_UPDATE(result, RET_ERROR_MISSING);
114+
+ }
115+
+ free(indexpath);
116+
+ free(basepath);
117+
+ strlist_done(&db_packages);
118+
+ strlist_done(&idx_packages);
119+
+ continue;
120+
+ }
121+
+ comp = c_gzip;
122+
+ free(basepath);
123+
+ basepath = NULL;
124+
+ }
125+
+
126+
+ r = indexfile_open(&idx, indexpath, comp);
127+
+ if (RET_WAS_ERROR(r)) {
128+
+ fprintf(stderr,
129+
+"Error: cannot open exported index file %s for %s!\n",
130+
+ indexpath, t->identifier);
131+
+ RET_UPDATE(result, r);
132+
+ goto target_done;
133+
+ }
134+
+
135+
+ memset(&pkg, 0, sizeof(pkg));
136+
+ while (indexfile_getnext(idx, &pkg, t, true)) {
137+
+ char *entry;
138+
+ entry = mprintf("%s|%s", pkg.name, pkg.version);
139+
+ if (FAILEDTOALLOC(entry)) {
140+
+ RET_UPDATE(result, RET_ERROR_OOM);
141+
+ mismatch = true;
142+
+ break;
143+
+ }
144+
+ r = strlist_add(&idx_packages, entry);
145+
+ if (RET_WAS_ERROR(r)) {
146+
+ free(entry);
147+
+ RET_UPDATE(result, r);
148+
+ mismatch = true;
149+
+ break;
150+
+ }
151+
+ package_done(&pkg);
152+
+ }
153+
+ package_done(&pkg);
154+
+
155+
+ r = indexfile_close(idx);
156+
+ idx = NULL;
157+
+ if (RET_WAS_ERROR(r)) {
158+
+ fprintf(stderr,
159+
+"Error: cannot close exported index file %s for %s!\n",
160+
+ indexpath, t->identifier);
161+
+ RET_UPDATE(result, r);
162+
+ goto target_done;
163+
+ }
164+
+ if (mismatch)
165+
+ goto target_done;
166+
+
167+
+ if (db_packages.count > 0)
168+
+ qsort(db_packages.values, db_packages.count,
169+
+ sizeof(char *),
170+
+ compare_string_pointers);
171+
+ if (idx_packages.count > 0)
172+
+ qsort(idx_packages.values, idx_packages.count,
173+
+ sizeof(char *),
174+
+ compare_string_pointers);
175+
+
176+
+ i = 0; j = 0;
177+
+ while (i < db_packages.count && j < idx_packages.count) {
178+
+ int cmp = strcmp(db_packages.values[i],
179+
+ idx_packages.values[j]);
180+
+ if (cmp == 0) {
181+
+ i++; j++;
182+
+ } else if (cmp < 0) {
183+
+ fprintf(stderr,
184+
+"Error: package missing in exported index %s: %s\n",
185+
+ t->identifier, db_packages.values[i]);
186+
+ mismatch = true;
187+
+ i++;
188+
+ } else {
189+
+ fprintf(stderr,
190+
+"Error: unexpected package in exported index %s: %s\n",
191+
+ t->identifier, idx_packages.values[j]);
192+
+ mismatch = true;
193+
+ j++;
194+
+ }
195+
+ }
196+
+ while (i < db_packages.count) {
197+
+ fprintf(stderr,
198+
+"Error: package missing in exported index %s: %s\n",
199+
+ t->identifier, db_packages.values[i]);
200+
+ mismatch = true;
201+
+ i++;
202+
+ }
203+
+ while (j < idx_packages.count) {
204+
+ fprintf(stderr,
205+
+"Error: unexpected package in exported index %s: %s\n",
206+
+ t->identifier, idx_packages.values[j]);
207+
+ mismatch = true;
208+
+ j++;
209+
+ }
210+
+
211+
+ if (mismatch) {
212+
+ fprintf(stderr,
213+
+"Fatal error: exported index %s does not match database!\n",
214+
+ t->identifier);
215+
+ RET_UPDATE(result, RET_ERROR);
216+
+ }
217+
+
218+
+ target_done:
219+
+ free(indexpath);
220+
+ free(basepath);
221+
+ strlist_done(&db_packages);
222+
+ strlist_done(&idx_packages);
223+
+ }
224+
+ }
225+
+
226+
+ return result;
227+
+}
228+
229+
/* get a pointer to the apropiate part of the linked list */
230+
struct distribution *distribution_find(struct distribution *distributions, const char *name) {
231+
diff --git a/distribution.h b/distribution.h
232+
index 1078084..9123764 100644
233+
--- a/distribution.h
234+
+++ b/distribution.h
235+
@@ -153,6 +153,7 @@ struct distribution *distribution_find(struct distribution *, const char *);
236+
retvalue distribution_freelist(/*@only@*/struct distribution *distributions);
237+
enum exportwhen {EXPORT_NEVER, EXPORT_SILENT_NEVER, EXPORT_CHANGED, EXPORT_NORMAL, EXPORT_FORCE };
238+
retvalue distribution_exportlist(enum exportwhen when, /*@only@*/struct distribution *);
239+
+retvalue distribution_verify_exported_indices(struct distribution *distributions);
240+
241+
retvalue distribution_loadalloverrides(struct distribution *);
242+
void distribution_unloadoverrides(struct distribution *distribution);
243+
diff --git a/main.c b/main.c
244+
index ad3f61a..c8570b8 100644
245+
--- a/main.c
246+
+++ b/main.c
247+
@@ -4266,6 +4266,16 @@ static retvalue callaction(command_t command, const struct action *action, int a
248+
if (!RET_WAS_ERROR(result)) {
249+
r = distribution_exportlist(export, alldistributions);
250+
RET_ENDUPDATE(result, r);
251+
+ /* verify exported index files match database
252+
+ * to catch inconsistencies caused by partial exports
253+
+ * or secondary index corruption (e.g. bug #1095493) */
254+
+ if (!RET_WAS_ERROR(result) &&
255+
+ export != EXPORT_NEVER &&
256+
+ export != EXPORT_SILENT_NEVER) {
257+
+ r = distribution_verify_exported_indices(
258+
+ alldistributions);
259+
+ RET_ENDUPDATE(result, r);
260+
+ }
261+
}
262+
263+
r = distribution_freelist(alldistributions);
264+
@@ -4402,6 +4412,16 @@ static retvalue callaction(command_t command, const struct action *action, int a
265+
r = distribution_exportlist(export,
266+
alldistributions);
267+
RET_ENDUPDATE(result, r);
268+
+ /* verify exported index files match database
269+
+ * to catch inconsistencies caused by partial exports
270+
+ * or secondary index corruption (e.g. bug #1095493) */
271+
+ if (!RET_WAS_ERROR(result) &&
272+
+ export != EXPORT_NEVER &&
273+
+ export != EXPORT_SILENT_NEVER) {
274+
+ r = distribution_verify_exported_indices(
275+
+ alldistributions);
276+
+ RET_ENDUPDATE(result, r);
277+
+ }
278+
}
279+
280+
/* delete files losing references, or

debian/patches/series

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
0002-feat-add-ignore-source-checksum-option-support.patch
33
0003-chore-Change-sha512-implement.patch
44
0004-fix-import-source-file-checksum-error.patch
5+
0005-feat-verify-exported-indices-consistency.patch

0 commit comments

Comments
 (0)