Skip to content

Commit 496bf14

Browse files
committed
bin/xbps-rindex: write all repodata's to tempfiles before renaming them all
1 parent 37f826e commit 496bf14

File tree

5 files changed

+118
-62
lines changed

5 files changed

+118
-62
lines changed

bin/xbps-rindex/defs.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,13 @@ int sign_repo(struct xbps_handle *, const char *, const char *,
4545
int sign_pkgs(struct xbps_handle *, int, int, char **, const char *, bool);
4646

4747
/* From repoflush.c */
48-
int repodata_flush(const char *repodir, const char *arch,
49-
xbps_dictionary_t index, xbps_dictionary_t stage, xbps_dictionary_t meta,
50-
const char *compression);
48+
int repodata_write_file(const char *repodir, const char *arch,
49+
xbps_dictionary_t index, xbps_dictionary_t stage, xbps_dictionary_t meta,
50+
const char *compression);
51+
int repodata_write_tmpfile(char *tmp, size_t tmpsz, char *path, size_t pathsz,
52+
const char *repodir, const char *arch, xbps_dictionary_t index,
53+
xbps_dictionary_t stage, xbps_dictionary_t meta, const char *compression);
54+
int repodata_write_fd(int fd, xbps_dictionary_t index, xbps_dictionary_t stage, xbps_dictionary_t meta,
55+
const char *compression);
5156

5257
#endif /* !_XBPS_RINDEX_DEFS_H_ */

bin/xbps-rindex/index-add.c

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*-
22
* Copyright (c) 2012-2015 Juan Romero Pardines.
3+
* Copyright (c) 2025 Duncan Overbruck <[email protected]>.
34
* All rights reserved.
45
*
56
* Redistribution and use in source and binary forms, with or without
@@ -41,6 +42,8 @@
4142
#include "defs.h"
4243

4344
struct repo {
45+
char path[PATH_MAX];
46+
char tmp[PATH_MAX];
4447
int lockfd;
4548
bool changed;
4649
const char *repodir;
@@ -698,24 +701,43 @@ index_add(struct xbps_handle *xhp, int argc, char **argv, bool force, const char
698701
if (r < 0)
699702
goto err;
700703

704+
// write all changed repodata's to tempfiles
701705
for (unsigned i = 0; i < nrepos; i++) {
702706
struct repo *repo = &repos[i];
703707
if (!repo->changed)
704708
continue;
705-
r = repodata_flush(repo->repodir, repo->arch, repo->index,
706-
repo->stage, repo->meta, compression);
709+
r = repodata_write_tmpfile(repo->path, sizeof(repo->path),
710+
repo->tmp, sizeof(repo->tmp), repo->repodir, repo->arch,
711+
repo->index, repo->stage, repo->meta, compression);
707712
if (r < 0)
708713
goto err;
709714
}
710715

716+
// rename all changed repodata's tempfiles
717+
for (unsigned i = 0; i < nrepos; i++) {
718+
struct repo *repo = &repos[i];
719+
if (!repo->changed)
720+
continue;
721+
if (rename(repo->tmp, repo->path) == -2) {
722+
xbps_error_printf("failed to rename tempfile: %s: %s: %s\n",
723+
repo->tmp, repo->path, strerror(-errno));
724+
// XXX: maybe better to abort here, but either way
725+
// we'll end up with inconsistent staging...
726+
}
727+
728+
}
729+
711730
for (unsigned i = 0; i < nrepos; i++)
712731
repo_state_release(&repos[i]);
713732
free(repos);
714733

715734
return EXIT_SUCCESS;
716735

717736
err:
718-
for (unsigned i = 0; i < nrepos; i++)
737+
for (unsigned i = 0; i < nrepos; i++) {
738+
if (repos[i].tmp[0] != 0)
739+
unlink(repos[i].tmp);
719740
repo_state_release(&repos[i]);
741+
}
720742
return EXIT_FAILURE;
721743
}

bin/xbps-rindex/index-clean.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ cleanup_repo(struct xbps_handle *xhp, const char *repodir, struct xbps_repo *rep
134134
return 0;
135135
}
136136

137-
r = repodata_flush(repodir, repoarch, index, stage, repo->idxmeta, compression);
137+
r = repodata_write_file(repodir, repoarch, index, stage, repo->idxmeta, compression);
138138
if (r < 0) {
139139
xbps_error_printf("failed to write repodata: %s\n", strerror(-r));
140140
xbps_object_release(index);

bin/xbps-rindex/repoflush.c

Lines changed: 83 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*-
22
* Copyright (c) 2013-2019 Juan Romero Pardines.
3-
* Copyright (c) 2023 Duncan Overbruck <[email protected]>.
3+
* Copyright (c) 2023-2025 Duncan Overbruck <[email protected]>.
44
* All rights reserved.
55
*
66
* Redistribution and use in source and binary forms, with or without
@@ -131,48 +131,17 @@ archive_dict(struct archive *ar, const char *filename, xbps_dictionary_t dict)
131131
}
132132

133133
int
134-
repodata_flush(const char *repodir,
135-
const char *arch,
136-
xbps_dictionary_t index,
137-
xbps_dictionary_t stage,
138-
xbps_dictionary_t meta,
139-
const char *compression)
134+
repodata_write_fd(int fd, xbps_dictionary_t index, xbps_dictionary_t stage,
135+
xbps_dictionary_t meta, const char *compression)
140136
{
141-
char path[PATH_MAX];
142-
char tmp[PATH_MAX];
143-
struct archive *ar = NULL;
144-
mode_t prevumask;
137+
struct archive *ar;
145138
int r;
146-
int fd;
147-
148-
r = snprintf(path, sizeof(path), "%s/%s-repodata", repodir, arch);
149-
if (r < 0 || (size_t)r >= sizeof(tmp)) {
150-
xbps_error_printf("repodata path too long: %s: %s\n", path,
151-
strerror(ENAMETOOLONG));
152-
return -ENAMETOOLONG;
153-
}
154-
155-
r = snprintf(tmp, sizeof(tmp), "%s.XXXXXXX", path);
156-
if (r < 0 || (size_t)r >= sizeof(tmp)) {
157-
xbps_error_printf("repodata tmp path too long: %s: %s\n", path,
158-
strerror(ENAMETOOLONG));
159-
return -ENAMETOOLONG;
160-
}
161-
162-
prevumask = umask(S_IXUSR|S_IRWXG|S_IRWXO);
163-
fd = mkstemp(tmp);
164-
if (fd == -1) {
165-
r = -errno;
166-
xbps_error_printf("failed to open temp file: %s: %s", tmp, strerror(-r));
167-
umask(prevumask);
168-
goto err;
169-
}
170-
umask(prevumask);
171139

172140
ar = open_archive(fd, compression);
173141
if (!ar) {
174142
r = -errno;
175-
goto err;
143+
xbps_error_printf("failed to open archive: %s\n", strerror(-r));
144+
return r;
176145
}
177146

178147
r = archive_dict(ar, XBPS_REPODATA_INDEX, index);
@@ -185,25 +154,72 @@ repodata_flush(const char *repodir,
185154
if (r < 0)
186155
goto err;
187156

188-
/* Write data to tempfile and rename */
157+
189158
if (archive_write_close(ar) == ARCHIVE_FATAL) {
190159
r = -archive_errno(ar);
191-
if (r == 1)
192-
r = -EINVAL;
193-
xbps_error_printf("failed to close archive: %s\n", archive_error_string(ar));
194-
goto err;
160+
xbps_error_printf(
161+
"failed to close archive: %s\n", archive_error_string(ar));
162+
archive_write_free(ar);
163+
return r;
195164
}
196165
if (archive_write_free(ar) == ARCHIVE_FATAL) {
197166
r = -errno;
198-
xbps_error_printf("failed to free archive: %s\n", strerror(-r));
199-
goto err;
167+
xbps_error_printf(
168+
"failed to free archive: %s\n", strerror(-r));
169+
archive_write_free(ar);
170+
return r;
200171
}
201172

202173
#ifdef HAVE_FDATASYNC
203174
fdatasync(fd);
204175
#else
205176
fsync(fd);
206177
#endif
178+
return 0;
179+
180+
err:
181+
archive_write_free(ar);
182+
return r;
183+
}
184+
185+
int
186+
repodata_write_tmpfile(char *path, size_t pathsz, char *tmp, size_t tmpsz,
187+
const char *repodir, const char *arch, xbps_dictionary_t index,
188+
xbps_dictionary_t stage, xbps_dictionary_t meta, const char *compression)
189+
{
190+
mode_t prevumask;
191+
int fd;
192+
int r;
193+
194+
r = snprintf(path, pathsz, "%s/%s-repodata", repodir, arch);
195+
if (r < 0 || (size_t)r >= pathsz) {
196+
xbps_error_printf("repodata path too long: %s: %s\n", path,
197+
strerror(ENAMETOOLONG));
198+
return -ENAMETOOLONG;
199+
}
200+
201+
r = snprintf(tmp, tmpsz, "%s.XXXXXXX", path);
202+
if (r < 0 || (size_t)r >= tmpsz) {
203+
xbps_error_printf("repodata tmp path too long: %s: %s\n", path,
204+
strerror(ENAMETOOLONG));
205+
return -ENAMETOOLONG;
206+
}
207+
208+
prevumask = umask(S_IXUSR|S_IRWXG|S_IRWXO);
209+
210+
fd = mkstemp(tmp);
211+
if (fd == -1) {
212+
r = -errno;
213+
xbps_error_printf("failed to open temp file: %s: %s", tmp, strerror(-r));
214+
umask(prevumask);
215+
goto err;
216+
}
217+
218+
umask(prevumask);
219+
220+
repodata_write_fd(fd, index, stage, meta, compression);
221+
if (r < 0)
222+
goto err;
207223

208224
if (fchmod(fd, 0664) == -1) {
209225
errno = -r;
@@ -215,22 +231,35 @@ repodata_flush(const char *repodir,
215231
}
216232
close(fd);
217233

234+
return 0;
235+
err:
236+
if (fd != -1)
237+
close(fd);
238+
unlink(tmp);
239+
return r;
240+
}
241+
242+
int
243+
repodata_write_file(const char *repodir, const char *arch,
244+
xbps_dictionary_t index, xbps_dictionary_t stage, xbps_dictionary_t meta,
245+
const char *compression)
246+
{
247+
char path[PATH_MAX];
248+
char tmp[PATH_MAX];
249+
int r;
250+
251+
r = repodata_write_tmpfile(path, sizeof(path), tmp, sizeof(tmp), repodir,
252+
arch, index, stage, meta, compression);
253+
if (r < 0)
254+
return r;
255+
218256
if (rename(tmp, path) == -1) {
219257
r = -errno;
220258
xbps_error_printf("failed to rename repodata: %s: %s: %s\n",
221259
tmp, path, strerror(-r));
222260
unlink(tmp);
223261
return r;
224262
}
225-
return 0;
226263

227-
err:
228-
if (ar) {
229-
archive_write_close(ar);
230-
archive_write_free(ar);
231-
}
232-
if (fd != -1)
233-
close(fd);
234-
unlink(tmp);
235-
return r;
264+
return 0;
236265
}

bin/xbps-rindex/sign.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ sign_repo(struct xbps_handle *xhp, const char *repodir,
230230
xbps_error_printf("cannot lock repository: %s\n", strerror(errno));
231231
goto out;
232232
}
233-
r = repodata_flush(repodir, repoarch, repo->index, repo->stage, meta, compression);
233+
r = repodata_write_file(repodir, repoarch, repo->index, repo->stage, meta, compression);
234234
xbps_repo_unlock(repodir, repoarch, lockfd);
235235
if (r < 0) {
236236
xbps_error_printf("failed to write repodata: %s\n", strerror(errno));

0 commit comments

Comments
 (0)