io: better error handling when writing stuff out
also have the output stream support writing to temporary file and do renameat/unlinkat on close depending on if all writes succeeded or not.cute-signatures
parent
bd9835a20e
commit
dee6ffa492
|
@ -46,7 +46,7 @@ struct apk_bstream {
|
||||||
|
|
||||||
struct apk_ostream {
|
struct apk_ostream {
|
||||||
ssize_t (*write)(void *stream, const void *buf, size_t size);
|
ssize_t (*write)(void *stream, const void *buf, size_t size);
|
||||||
void (*close)(void *stream);
|
int (*close)(void *stream);
|
||||||
};
|
};
|
||||||
|
|
||||||
#define APK_MPART_DATA 1 /* data processed so far */
|
#define APK_MPART_DATA 1 /* data processed so far */
|
||||||
|
@ -81,8 +81,8 @@ struct apk_bstream *apk_bstream_from_url(const char *url);
|
||||||
struct apk_bstream *apk_bstream_tee(struct apk_bstream *from, int atfd, const char *to);
|
struct apk_bstream *apk_bstream_tee(struct apk_bstream *from, int atfd, const char *to);
|
||||||
|
|
||||||
struct apk_ostream *apk_ostream_to_fd(int fd);
|
struct apk_ostream *apk_ostream_to_fd(int fd);
|
||||||
struct apk_ostream *apk_ostream_to_file(int atfd, const char *file, mode_t mode);
|
struct apk_ostream *apk_ostream_to_file(int atfd, const char *file, const char *tmpfile, mode_t mode);
|
||||||
struct apk_ostream *apk_ostream_to_file_gz(int atfd, const char *file, mode_t mode);
|
struct apk_ostream *apk_ostream_to_file_gz(int atfd, const char *file, const char *tmpfile, mode_t mode);
|
||||||
size_t apk_ostream_write_string(struct apk_ostream *ostream, const char *string);
|
size_t apk_ostream_write_string(struct apk_ostream *ostream, const char *string);
|
||||||
|
|
||||||
apk_blob_t apk_blob_from_istream(struct apk_istream *istream, size_t size);
|
apk_blob_t apk_blob_from_istream(struct apk_istream *istream, size_t size);
|
||||||
|
|
|
@ -814,7 +814,10 @@ static int apk_db_index_write_nr_cache(struct apk_database *db)
|
||||||
|
|
||||||
/* Write list of installed non-repository packages to
|
/* Write list of installed non-repository packages to
|
||||||
* cached index file */
|
* cached index file */
|
||||||
os = apk_ostream_to_file(db->cache_fd, "installed.new", 0644);
|
os = apk_ostream_to_file(db->cache_fd,
|
||||||
|
"installed",
|
||||||
|
"installed.new",
|
||||||
|
0644);
|
||||||
if (os == NULL)
|
if (os == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
@ -826,11 +829,9 @@ static int apk_db_index_write_nr_cache(struct apk_database *db)
|
||||||
if (r != 0)
|
if (r != 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
r = os->close(os);
|
||||||
os->close(os);
|
if (r < 0)
|
||||||
if (renameat(db->cache_fd, "installed.new",
|
return r;
|
||||||
db->cache_fd, "installed") < 0)
|
|
||||||
return -errno;
|
|
||||||
|
|
||||||
return ctx.count;
|
return ctx.count;
|
||||||
}
|
}
|
||||||
|
@ -1020,6 +1021,7 @@ struct write_ctx {
|
||||||
int apk_db_write_config(struct apk_database *db)
|
int apk_db_write_config(struct apk_database *db)
|
||||||
{
|
{
|
||||||
struct apk_ostream *os;
|
struct apk_ostream *os;
|
||||||
|
int r;
|
||||||
|
|
||||||
if (db->root == NULL)
|
if (db->root == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1029,34 +1031,40 @@ int apk_db_write_config(struct apk_database *db)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
os = apk_ostream_to_file(db->root_fd, "var/lib/apk/world.new", 0644);
|
os = apk_ostream_to_file(db->root_fd,
|
||||||
|
"var/lib/apk/world",
|
||||||
|
"var/lib/apk/world.new",
|
||||||
|
0644);
|
||||||
if (os == NULL)
|
if (os == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
apk_deps_write(db->world, os);
|
apk_deps_write(db->world, os);
|
||||||
os->write(os, "\n", 1);
|
os->write(os, "\n", 1);
|
||||||
os->close(os);
|
r = os->close(os);
|
||||||
if (renameat(db->root_fd, "var/lib/apk/world.new",
|
if (r < 0)
|
||||||
db->root_fd, "var/lib/apk/world") < 0)
|
return r;
|
||||||
return -errno;
|
|
||||||
|
|
||||||
os = apk_ostream_to_file(db->root_fd, "var/lib/apk/installed.new", 0644);
|
os = apk_ostream_to_file(db->root_fd,
|
||||||
|
"var/lib/apk/installed",
|
||||||
|
"var/lib/apk/installed.new",
|
||||||
|
0644);
|
||||||
if (os == NULL)
|
if (os == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
apk_db_write_fdb(db, os);
|
apk_db_write_fdb(db, os);
|
||||||
os->close(os);
|
r = os->close(os);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
if (renameat(db->root_fd, "var/lib/apk/installed.new",
|
os = apk_ostream_to_file(db->root_fd,
|
||||||
db->root_fd, "var/lib/apk/installed") < 0)
|
"var/lib/apk/scripts.tar",
|
||||||
return -errno;
|
"var/lib/apk/scripts.tar.new",
|
||||||
|
0644);
|
||||||
os = apk_ostream_to_file(db->root_fd, "var/lib/apk/scripts.tar.new", 0644);
|
|
||||||
if (os == NULL)
|
if (os == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
apk_db_scriptdb_write(db, os);
|
apk_db_scriptdb_write(db, os);
|
||||||
os->close(os);
|
r = os->close(os);
|
||||||
if (renameat(db->root_fd, "var/lib/apk/scripts.tar.new",
|
if (r < 0)
|
||||||
db->root_fd, "var/lib/apk/scripts.tar") < 0)
|
return r;
|
||||||
return -errno;
|
|
||||||
|
|
||||||
unlinkat(db->root_fd, "var/lib/apk/scripts", 0);
|
unlinkat(db->root_fd, "var/lib/apk/scripts", 0);
|
||||||
apk_db_index_write_nr_cache(db);
|
apk_db_index_write_nr_cache(db);
|
||||||
|
@ -1796,6 +1804,13 @@ static int apk_db_unpack_pkg(struct apk_database *db,
|
||||||
if (ctx.replaces)
|
if (ctx.replaces)
|
||||||
free(ctx.replaces);
|
free(ctx.replaces);
|
||||||
|
|
||||||
|
if (need_copy) {
|
||||||
|
if (r == 0)
|
||||||
|
renameat(db->cachetmp_fd, file, db->cache_fd, file);
|
||||||
|
else
|
||||||
|
unlinkat(db->cachetmp_fd, file, 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (r != 0) {
|
if (r != 0) {
|
||||||
apk_error("%s-%s: %s",
|
apk_error("%s-%s: %s",
|
||||||
newpkg->name->name, newpkg->version,
|
newpkg->name->name, newpkg->version,
|
||||||
|
@ -1808,9 +1823,6 @@ static int apk_db_unpack_pkg(struct apk_database *db,
|
||||||
|
|
||||||
apk_db_migrate_files(db, newpkg);
|
apk_db_migrate_files(db, newpkg);
|
||||||
|
|
||||||
if (need_copy)
|
|
||||||
renameat(db->cachetmp_fd, file, db->cache_fd, file);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
err:
|
err:
|
||||||
if (!reinstall)
|
if (!reinstall)
|
||||||
|
|
13
src/gunzip.c
13
src/gunzip.c
|
@ -190,24 +190,29 @@ static ssize_t gzo_write(void *stream, const void *ptr, size_t size)
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gzo_close(void *stream)
|
static int gzo_close(void *stream)
|
||||||
{
|
{
|
||||||
struct apk_gzip_ostream *gos = (struct apk_gzip_ostream *) stream;
|
struct apk_gzip_ostream *gos = (struct apk_gzip_ostream *) stream;
|
||||||
unsigned char buffer[1024];
|
unsigned char buffer[1024];
|
||||||
size_t have;
|
size_t have;
|
||||||
int r;
|
int r, rc = 0;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
gos->zs.avail_out = sizeof(buffer);
|
gos->zs.avail_out = sizeof(buffer);
|
||||||
gos->zs.next_out = buffer;
|
gos->zs.next_out = buffer;
|
||||||
r = deflate(&gos->zs, Z_FINISH);
|
r = deflate(&gos->zs, Z_FINISH);
|
||||||
have = sizeof(buffer) - gos->zs.avail_out;
|
have = sizeof(buffer) - gos->zs.avail_out;
|
||||||
gos->output->write(gos->output, buffer, have);
|
if (gos->output->write(gos->output, buffer, have) != have)
|
||||||
|
rc = -EIO;
|
||||||
} while (r == Z_OK);
|
} while (r == Z_OK);
|
||||||
gos->output->close(gos->output);
|
r = gos->output->close(gos->output);
|
||||||
|
if (r != 0)
|
||||||
|
rc = r;
|
||||||
|
|
||||||
deflateEnd(&gos->zs);
|
deflateEnd(&gos->zs);
|
||||||
free(stream);
|
free(stream);
|
||||||
|
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct apk_ostream *apk_ostream_gzip(struct apk_ostream *output)
|
struct apk_ostream *apk_ostream_gzip(struct apk_ostream *output)
|
||||||
|
|
|
@ -169,7 +169,7 @@ static int index_main(void *ctx, struct apk_database *db, int argc, char **argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ictx->output != NULL)
|
if (ictx->output != NULL)
|
||||||
os = apk_ostream_to_file(AT_FDCWD, ictx->output, 0644);
|
os = apk_ostream_to_file(AT_FDCWD, ictx->output, NULL, 0644);
|
||||||
else
|
else
|
||||||
os = apk_ostream_to_fd(STDOUT_FILENO);
|
os = apk_ostream_to_fd(STDOUT_FILENO);
|
||||||
if (ictx->method == APK_SIGN_GENERATE) {
|
if (ictx->method == APK_SIGN_GENERATE) {
|
||||||
|
|
68
src/io.c
68
src/io.c
|
@ -65,8 +65,10 @@ struct apk_istream *apk_istream_from_fd(int fd)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
fis = malloc(sizeof(struct apk_fd_istream));
|
fis = malloc(sizeof(struct apk_fd_istream));
|
||||||
if (fis == NULL)
|
if (fis == NULL) {
|
||||||
|
close(fd);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
*fis = (struct apk_fd_istream) {
|
*fis = (struct apk_fd_istream) {
|
||||||
.is.read = fdi_read,
|
.is.read = fdi_read,
|
||||||
|
@ -527,7 +529,11 @@ struct apk_istream *apk_istream_from_file_gz(int atfd, const char *file)
|
||||||
|
|
||||||
struct apk_fd_ostream {
|
struct apk_fd_ostream {
|
||||||
struct apk_ostream os;
|
struct apk_ostream os;
|
||||||
int fd;
|
int fd, rc;
|
||||||
|
|
||||||
|
const char *file, *tmpfile;
|
||||||
|
int atfd;
|
||||||
|
|
||||||
size_t bytes;
|
size_t bytes;
|
||||||
char buffer[1024];
|
char buffer[1024];
|
||||||
};
|
};
|
||||||
|
@ -555,8 +561,10 @@ static ssize_t fdo_flush(struct apk_fd_ostream *fos)
|
||||||
if (fos->bytes == 0)
|
if (fos->bytes == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if ((r = safe_write(fos->fd, fos->buffer, fos->bytes)) != fos->bytes)
|
if ((r = safe_write(fos->fd, fos->buffer, fos->bytes)) != fos->bytes) {
|
||||||
|
fos->rc = r < 0 ? r : -EIO;
|
||||||
return r;
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
fos->bytes = 0;
|
fos->bytes = 0;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -572,8 +580,12 @@ static ssize_t fdo_write(void *stream, const void *ptr, size_t size)
|
||||||
r = fdo_flush(fos);
|
r = fdo_flush(fos);
|
||||||
if (r != 0)
|
if (r != 0)
|
||||||
return r;
|
return r;
|
||||||
if (size >= sizeof(fos->buffer) / 2)
|
if (size >= sizeof(fos->buffer) / 2) {
|
||||||
return safe_write(fos->fd, ptr, size);
|
r = safe_write(fos->fd, ptr, size);
|
||||||
|
if (r != size)
|
||||||
|
fos->rc = r < 0 ? r : -EIO;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(&fos->buffer[fos->bytes], ptr, size);
|
memcpy(&fos->buffer[fos->bytes], ptr, size);
|
||||||
|
@ -582,14 +594,28 @@ static ssize_t fdo_write(void *stream, const void *ptr, size_t size)
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fdo_close(void *stream)
|
static int fdo_close(void *stream)
|
||||||
{
|
{
|
||||||
struct apk_fd_ostream *fos =
|
struct apk_fd_ostream *fos =
|
||||||
container_of(stream, struct apk_fd_ostream, os);
|
container_of(stream, struct apk_fd_ostream, os);
|
||||||
|
int rc = fos->rc;
|
||||||
|
|
||||||
fdo_flush(fos);
|
fdo_flush(fos);
|
||||||
close(fos->fd);
|
if (fos->fd > STDERR_FILENO &&
|
||||||
|
close(fos->fd) < 0)
|
||||||
|
rc = -errno;
|
||||||
|
|
||||||
|
if (fos->tmpfile != NULL) {
|
||||||
|
if (rc == 0)
|
||||||
|
renameat(fos->atfd, fos->tmpfile,
|
||||||
|
fos->atfd, fos->file);
|
||||||
|
else
|
||||||
|
unlinkat(fos->atfd, fos->tmpfile, 0);
|
||||||
|
}
|
||||||
|
|
||||||
free(fos);
|
free(fos);
|
||||||
|
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct apk_ostream *apk_ostream_to_fd(int fd)
|
struct apk_ostream *apk_ostream_to_fd(int fd)
|
||||||
|
@ -600,8 +626,10 @@ struct apk_ostream *apk_ostream_to_fd(int fd)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
fos = malloc(sizeof(struct apk_fd_ostream));
|
fos = malloc(sizeof(struct apk_fd_ostream));
|
||||||
if (fos == NULL)
|
if (fos == NULL) {
|
||||||
|
close(fd);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
*fos = (struct apk_fd_ostream) {
|
*fos = (struct apk_fd_ostream) {
|
||||||
.os.write = fdo_write,
|
.os.write = fdo_write,
|
||||||
|
@ -612,17 +640,32 @@ struct apk_ostream *apk_ostream_to_fd(int fd)
|
||||||
return &fos->os;
|
return &fos->os;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct apk_ostream *apk_ostream_to_file(int atfd, const char *file, mode_t mode)
|
struct apk_ostream *apk_ostream_to_file(int atfd,
|
||||||
|
const char *file,
|
||||||
|
const char *tmpfile,
|
||||||
|
mode_t mode)
|
||||||
{
|
{
|
||||||
|
struct apk_ostream *os;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
fd = openat(atfd, file, O_CREAT | O_RDWR | O_TRUNC, mode);
|
fd = openat(atfd, tmpfile ?: file, O_CREAT | O_RDWR | O_TRUNC, mode);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
fcntl(fd, F_SETFD, FD_CLOEXEC);
|
fcntl(fd, F_SETFD, FD_CLOEXEC);
|
||||||
|
|
||||||
return apk_ostream_to_fd(fd);
|
os = apk_ostream_to_fd(fd);
|
||||||
|
if (os == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (tmpfile != NULL) {
|
||||||
|
struct apk_fd_ostream *fos =
|
||||||
|
container_of(os, struct apk_fd_ostream, os);
|
||||||
|
fos->file = file;
|
||||||
|
fos->tmpfile = tmpfile;
|
||||||
|
fos->atfd = atfd;
|
||||||
|
}
|
||||||
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct apk_counter_ostream {
|
struct apk_counter_ostream {
|
||||||
|
@ -639,12 +682,13 @@ static ssize_t co_write(void *stream, const void *ptr, size_t size)
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void co_close(void *stream)
|
static int co_close(void *stream)
|
||||||
{
|
{
|
||||||
struct apk_counter_ostream *cos =
|
struct apk_counter_ostream *cos =
|
||||||
container_of(stream, struct apk_counter_ostream, os);
|
container_of(stream, struct apk_counter_ostream, os);
|
||||||
|
|
||||||
free(cos);
|
free(cos);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct apk_ostream *apk_ostream_counter(off_t *counter)
|
struct apk_ostream *apk_ostream_counter(off_t *counter)
|
||||||
|
|
Loading…
Reference in New Issue