Commit 97583475 authored by Bernhard Link's avatar Bernhard Link

move Release file finalisation from signedfile to release

parent 9f703be1
2012-12-15 Bernhard R. Link <brlink@debian.org>
* move around some of the code related to moving
(In)Release(.gpg) to it's final place. Side effect
is that those files are removed if there are no longer
requested.
2012-12-09 Bernhard R. Link <brlink@debian.org>
* unify export handling (moving it out of the
action specific code)
......
......@@ -82,6 +82,17 @@ struct release {
struct table *cachedb;
};
static void release_freeentry(struct release_entry *e) {
free(e->relativefilename);
checksums_free(e->checksums);
free(e->fullfinalfilename);
if (!global.keeptemporaries && e->fulltemporaryfilename != NULL)
(void)unlink(e->fulltemporaryfilename);
free(e->fulltemporaryfilename);
free(e->symlinktarget);
free(e);
}
void release_free(struct release *release) {
struct release_entry *e;
......@@ -90,17 +101,10 @@ void release_free(struct release *release) {
free(release->fakecodename);
while ((e = release->files) != NULL) {
release->files = e->next;
free(e->relativefilename);
checksums_free(e->checksums);
free(e->fullfinalfilename);
if (!global.keeptemporaries && e->fulltemporaryfilename != NULL)
unlink(e->fulltemporaryfilename);
free(e->fulltemporaryfilename);
free(e->symlinktarget);
free(e);
release_freeentry(e);
}
if (release->signedfile != NULL)
signedfile_free(release->signedfile, !global.keeptemporaries);
signedfile_free(release->signedfile);
if (release->cachedb != NULL) {
table_close(release->cachedb);
}
......@@ -1324,6 +1328,56 @@ static inline bool componentneedsfake(const char *cn, const struct release *rele
return cn[release->fakecomponentprefixlen] != '/';
}
static struct release_entry *newspecialreleaseentry(struct release *release, const char *relativefilename) {
struct release_entry *n, *p;
assert (relativefilename != NULL);
n = zNEW(struct release_entry);
if (FAILEDTOALLOC(n))
return NULL;
n->relativefilename = strdup(relativefilename);
n->fullfinalfilename = calc_dirconcat(release->dirofdist,
relativefilename);
if (!FAILEDTOALLOC(n->fullfinalfilename))
n->fulltemporaryfilename = mprintf("%s.new",
n->fullfinalfilename);
if (FAILEDTOALLOC(n->relativefilename)
|| FAILEDTOALLOC(n->fullfinalfilename)
|| FAILEDTOALLOC(n->fulltemporaryfilename)) {
release_freeentry(n);
return NULL;
}
if (release->files == NULL)
release->files = n;
else {
p = release->files;
while (p->next != NULL)
p = p->next;
p->next = n;
}
return n;
}
static void omitunusedspecialreleaseentry(struct release *release, struct release_entry *e) {
struct release_entry **p;
if (e->fulltemporaryfilename != NULL)
/* new file available, nothing to omit */
return;
if (isregularfile(e->fullfinalfilename))
/* this will be deleted, everything fine */
return;
p = &release->files;
while (*p != NULL && *p != e)
p = &(*p)->next;
if (*p != e) {
assert (*p == e);
return;
}
*p = e->next;
release_freeentry(e);
}
/* Generate a main "Release" file for a distribution */
retvalue release_prepare(struct release *release, struct distribution *distribution, bool onlyifneeded) {
size_t s;
......@@ -1336,6 +1390,7 @@ retvalue release_prepare(struct release *release, struct distribution *distribut
int i;
static const char * const release_checksum_headers[cs_hashCOUNT] =
{ "MD5Sum:\n", "SHA1:\n", "SHA256:\n" };
struct release_entry *plainentry, *signedentry, *detachedentry;
// TODO: check for existance of Release file here first?
if (onlyifneeded && !release->new) {
......@@ -1363,12 +1418,18 @@ retvalue release_prepare(struct release *release, struct distribution *distribut
return RET_ERROR;
}
}
r = signature_startsignedfile(release->dirofdist,
"Release", "InRelease",
&release->signedfile);
if (RET_WAS_ERROR(r)) {
plainentry = newspecialreleaseentry(release, "Release");
if (FAILEDTOALLOC(plainentry))
return RET_ERROR_OOM;
signedentry = newspecialreleaseentry(release, "InRelease");
if (FAILEDTOALLOC(signedentry))
return RET_ERROR_OOM;
detachedentry = newspecialreleaseentry(release, "Release.gpg");
if (FAILEDTOALLOC(signedentry))
return RET_ERROR_OOM;
r = signature_startsignedfile(&release->signedfile);
if (RET_WAS_ERROR(r))
return r;
}
#define writestring(s) signedfile_write(release->signedfile, s, strlen(s))
#define writechar(c) {char __c = c ; signedfile_write(release->signedfile, &__c, 1); }
......@@ -1463,13 +1524,18 @@ retvalue release_prepare(struct release *release, struct distribution *distribut
writechar('\n');
}
}
r = signedfile_prepare(release->signedfile, &distribution->signwith,
!global.keeptemporaries);
r = signedfile_create(release->signedfile,
plainentry->fulltemporaryfilename,
&signedentry->fulltemporaryfilename,
&detachedentry->fulltemporaryfilename,
&distribution->signwith, !global.keeptemporaries);
if (RET_WAS_ERROR(r)) {
signedfile_free(release->signedfile, !global.keeptemporaries);
signedfile_free(release->signedfile);
release->signedfile = NULL;
return r;
}
omitunusedspecialreleaseentry(release, signedentry);
omitunusedspecialreleaseentry(release, detachedentry);
return RET_OK;
}
......@@ -1548,12 +1614,6 @@ retvalue release_finish(/*@only@*/struct release *release, struct distribution *
}
}
}
r = signedfile_finalize(release->signedfile, &somethingwasdone);
if (RET_WAS_ERROR(r) && !somethingwasdone) {
release_free(release);
return r;
}
RET_UPDATE(result, r);
if (RET_WAS_ERROR(result) && somethingwasdone) {
fprintf(stderr,
"ATTENTION: some files were already moved to place, some could not be.\n"
......
......@@ -56,14 +56,11 @@ retvalue signature_readsignedchunk(const char *filename, const char *filenametos
struct signedfile;
struct strlist;
retvalue signature_startsignedfile(const char */*directory*/, const char */*basename*/, const char */*inlinebasename*/, /*@out@*/struct signedfile **);
retvalue signature_startsignedfile(/*@out@*/struct signedfile **);
void signedfile_write(struct signedfile *, const void *, size_t);
/* generate signature in temporary file */
retvalue signedfile_prepare(struct signedfile *, const struct strlist *, bool /*willcleanup*/);
/* move temporary files to final places */
retvalue signedfile_finalize(struct signedfile *, bool *toolate);
/* may only be called after signedfile_prepare */
void signedfile_free(/*@only@*/struct signedfile *, bool cleanup);
retvalue signedfile_create(struct signedfile *, const char *, char **, char **, const struct strlist *, bool /*willcleanup*/);
void signedfile_free(/*@only@*/struct signedfile *);
void signatures_done(void);
#endif
......@@ -342,39 +342,22 @@ static retvalue signature_with_extern(const struct strlist *options, const char
}
struct signedfile {
char *plainfilename, *newplainfilename;
char *signfilename, *newsignfilename;
char *inlinefilename, *newinlinefilename;
retvalue result;
#define DATABUFFERUNITS (128ul * 1024ul)
size_t bufferlen, buffersize;
char *buffer;
};
retvalue signature_startsignedfile(const char *directory, const char *basefilename, const char *inlinefilename, struct signedfile **out) {
retvalue signature_startsignedfile(struct signedfile **out) {
struct signedfile *n;
n = zNEW(struct signedfile);
if (FAILEDTOALLOC(n))
return RET_ERROR_OOM;
n->plainfilename = calc_dirconcat(directory, basefilename);
if (FAILEDTOALLOC(n->plainfilename)) {
free(n);
return RET_ERROR_OOM;
}
n->inlinefilename = calc_dirconcat(directory, inlinefilename);
if (FAILEDTOALLOC(n->inlinefilename)) {
free(n->plainfilename);
free(n);
return RET_ERROR_OOM;
}
n->newplainfilename = NULL;
n->bufferlen = 0;
n->buffersize = DATABUFFERUNITS;
n->buffer = malloc(n->buffersize);
if (FAILEDTOALLOC(n->buffer)) {
free(n->plainfilename);
free(n->inlinefilename);
free(n);
return RET_ERROR_OOM;
}
......@@ -382,27 +365,9 @@ retvalue signature_startsignedfile(const char *directory, const char *basefilena
return RET_OK;
}
void signedfile_free(struct signedfile *f, bool cleanup) {
void signedfile_free(struct signedfile *f) {
if (f == NULL)
return;
if (f->newplainfilename != NULL) {
if (cleanup)
(void)unlink(f->newplainfilename);
free(f->newplainfilename);
}
free(f->plainfilename);
if (f->newsignfilename != NULL) {
if (cleanup)
(void)unlink(f->newsignfilename);
free(f->newsignfilename);
}
free(f->signfilename);
if (f->newinlinefilename != NULL) {
if (cleanup)
(void)unlink(f->newinlinefilename);
free(f->newinlinefilename);
}
free(f->inlinefilename);
free(f->buffer);
free(f);
return;
......@@ -439,7 +404,7 @@ void signedfile_write(struct signedfile *f, const void *data, size_t len) {
assert (f->bufferlen <= f->buffersize);
}
retvalue signedfile_prepare(struct signedfile *f, const struct strlist *options, bool willcleanup) {
retvalue signedfile_create(struct signedfile *f, const char *newplainfilename, char **newsignedfilename_p, char **newdetachedsignature_p, const struct strlist *options, bool willcleanup) {
size_t len, ofs;
int fd, ret;
......@@ -448,21 +413,17 @@ retvalue signedfile_prepare(struct signedfile *f, const struct strlist *options,
/* write content to file */
f->newplainfilename = calc_addsuffix(f->plainfilename, "new");
if (FAILEDTOALLOC(f->newplainfilename))
return RET_ERROR_OOM;
assert (newplainfilename != NULL);
(void)dirs_make_parent(f->newplainfilename);
(void)unlink(f->newplainfilename);
(void)dirs_make_parent(newplainfilename);
(void)unlink(newplainfilename);
fd = open(f->newplainfilename, O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY, 0666);
fd = open(newplainfilename, O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY, 0666);
if (fd < 0) {
int e = errno;
fprintf(stderr, "Error creating file '%s': %s\n",
f->newplainfilename,
newplainfilename,
strerror(e));
free(f->newplainfilename);
f->newplainfilename = NULL;
return RET_ERRNO(e);
}
ofs = 0;
......@@ -474,12 +435,9 @@ retvalue signedfile_prepare(struct signedfile *f, const struct strlist *options,
if (written < 0) {
int e = errno;
fprintf(stderr, "Error %d writing to file '%s': %s\n",
e, f->newplainfilename,
e, newplainfilename,
strerror(e));
(void)close(fd);
(void)unlink(f->newplainfilename);
free(f->newplainfilename);
f->newplainfilename = NULL;
return RET_ERRNO(e);
}
assert ((size_t)written <= len);
......@@ -490,53 +448,39 @@ retvalue signedfile_prepare(struct signedfile *f, const struct strlist *options,
if (ret < 0) {
int e = errno;
fprintf(stderr, "Error %d writing to file '%s': %s\n",
e, f->newplainfilename,
e, newplainfilename,
strerror(e));
(void)unlink(f->newplainfilename);
free(f->newplainfilename);
f->newplainfilename = NULL;
return RET_ERRNO(e);
}
/* now do the actual signing */
if (options != NULL && options->count > 0) {
retvalue r;
assert (f->newplainfilename != NULL);
f->signfilename = calc_addsuffix(f->plainfilename, "gpg");
if (FAILEDTOALLOC(f->signfilename))
return RET_ERROR_OOM;
f->newsignfilename = calc_addsuffix(f->signfilename, "new");
if (FAILEDTOALLOC(f->newsignfilename))
return RET_ERROR_OOM;
f->newinlinefilename = calc_addsuffix(f->inlinefilename, "new");
if (FAILEDTOALLOC(f->newinlinefilename))
return RET_ERROR_OOM;
const char *newsigned = *newsignedfilename_p;
const char *newdetached = *newdetachedsignature_p;
/* make sure the new files do not already exist: */
if (unlink(f->newsignfilename) != 0 && errno != ENOENT) {
if (unlink(newdetached) != 0 && errno != ENOENT) {
fprintf(stderr,
"Could not remove '%s' to prepare replacement: %s\n",
f->newsignfilename, strerror(errno));
newdetached, strerror(errno));
return RET_ERROR;
}
if (unlink(f->newinlinefilename) != 0 && errno != ENOENT) {
if (unlink(newsigned) != 0 && errno != ENOENT) {
fprintf(stderr,
"Could not remove '%s' to prepare replacement: %s\n",
f->newinlinefilename, strerror(errno));
newsigned, strerror(errno));
return RET_ERROR;
}
/* if an hook is given, use that instead */
if (options->values[0][0] == '!')
r = signature_with_extern(options, f->newplainfilename,
f->newinlinefilename,
&f->newsignfilename);
r = signature_with_extern(options, newplainfilename,
newsigned, newdetachedsignature_p);
else
#ifdef HAVE_LIBGPGME
r = signature_sign(options,
f->newplainfilename,
newplainfilename,
f->buffer, f->bufferlen,
f->newsignfilename,
f->newinlinefilename,
newdetached, newsigned,
willcleanup);
#else /* HAVE_LIBGPGME */
fputs(
......@@ -547,67 +491,12 @@ retvalue signedfile_prepare(struct signedfile *f, const struct strlist *options,
#endif
if (RET_WAS_ERROR(r))
return r;
}
return RET_OK;
}
retvalue signedfile_finalize(struct signedfile *f, bool *toolate) {
retvalue result = RET_OK, r;
int e;
if (f->newsignfilename != NULL && f->signfilename != NULL) {
e = rename(f->newsignfilename, f->signfilename);
if (e < 0) {
e = errno;
fprintf(stderr, "Error %d moving %s to %s: %s!\n", e,
f->newsignfilename,
f->signfilename, strerror(e));
result = RET_ERRNO(e);
/* after something was done, do not stop
* but try to do as much as possible */
if (!*toolate)
return result;
} else {
/* does not need deletion any more */
free(f->newsignfilename);
f->newsignfilename = NULL;
*toolate = true;
}
} else if (f->newsignfilename == NULL && f->signfilename != NULL) {
(void)unlink(f->signfilename);
}
if (f->newinlinefilename != NULL && f->inlinefilename != NULL) {
e = rename(f->newinlinefilename, f->inlinefilename);
if (e < 0) {
e = errno;
fprintf(stderr, "Error %d moving %s to %s: %s!\n", e,
f->newinlinefilename,
f->inlinefilename, strerror(e));
result = RET_ERRNO(e);
/* after something was done, do not stop
* but try to do as much as possible */
if (!*toolate)
return result;
} else {
/* does not need deletion any more */
free(f->newinlinefilename);
f->newinlinefilename = NULL;
*toolate = true;
}
} else if (f->newinlinefilename == NULL && f->inlinefilename != NULL) {
(void)unlink(f->inlinefilename);
}
e = rename(f->newplainfilename, f->plainfilename);
if (e < 0) {
e = errno;
fprintf(stderr, "Error %d moving %s to %s: %s!\n", e,
f->newplainfilename,
f->plainfilename, strerror(e));
r = RET_ERRNO(e);
RET_UPDATE(result, r);
} else {
free(f->newplainfilename);
f->newplainfilename = NULL;
/* no signatures requested */
free(*newsignedfilename_p);
*newsignedfilename_p = NULL;
free(*newdetachedsignature_p);
*newdetachedsignature_p = NULL;
}
return result;
return RET_OK;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment