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 {
|
||||
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 */
|
||||
|
@ -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_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_gz(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, const char *tmpfile, mode_t mode);
|
||||
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);
|
||||
|
|
|
@ -814,7 +814,10 @@ static int apk_db_index_write_nr_cache(struct apk_database *db)
|
|||
|
||||
/* Write list of installed non-repository packages to
|
||||
* 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)
|
||||
return -1;
|
||||
|
||||
|
@ -826,11 +829,9 @@ static int apk_db_index_write_nr_cache(struct apk_database *db)
|
|||
if (r != 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
os->close(os);
|
||||
if (renameat(db->cache_fd, "installed.new",
|
||||
db->cache_fd, "installed") < 0)
|
||||
return -errno;
|
||||
r = os->close(os);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return ctx.count;
|
||||
}
|
||||
|
@ -1020,6 +1021,7 @@ struct write_ctx {
|
|||
int apk_db_write_config(struct apk_database *db)
|
||||
{
|
||||
struct apk_ostream *os;
|
||||
int r;
|
||||
|
||||
if (db->root == NULL)
|
||||
return 0;
|
||||
|
@ -1029,34 +1031,40 @@ int apk_db_write_config(struct apk_database *db)
|
|||
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)
|
||||
return -1;
|
||||
|
||||
apk_deps_write(db->world, os);
|
||||
os->write(os, "\n", 1);
|
||||
os->close(os);
|
||||
if (renameat(db->root_fd, "var/lib/apk/world.new",
|
||||
db->root_fd, "var/lib/apk/world") < 0)
|
||||
return -errno;
|
||||
r = os->close(os);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
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)
|
||||
return -1;
|
||||
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",
|
||||
db->root_fd, "var/lib/apk/installed") < 0)
|
||||
return -errno;
|
||||
|
||||
os = apk_ostream_to_file(db->root_fd, "var/lib/apk/scripts.tar.new", 0644);
|
||||
os = apk_ostream_to_file(db->root_fd,
|
||||
"var/lib/apk/scripts.tar",
|
||||
"var/lib/apk/scripts.tar.new",
|
||||
0644);
|
||||
if (os == NULL)
|
||||
return -1;
|
||||
apk_db_scriptdb_write(db, os);
|
||||
os->close(os);
|
||||
if (renameat(db->root_fd, "var/lib/apk/scripts.tar.new",
|
||||
db->root_fd, "var/lib/apk/scripts.tar") < 0)
|
||||
return -errno;
|
||||
r = os->close(os);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
unlinkat(db->root_fd, "var/lib/apk/scripts", 0);
|
||||
apk_db_index_write_nr_cache(db);
|
||||
|
@ -1796,6 +1804,13 @@ static int apk_db_unpack_pkg(struct apk_database *db,
|
|||
if (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) {
|
||||
apk_error("%s-%s: %s",
|
||||
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);
|
||||
|
||||
if (need_copy)
|
||||
renameat(db->cachetmp_fd, file, db->cache_fd, file);
|
||||
|
||||
return 0;
|
||||
err:
|
||||
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;
|
||||
}
|
||||
|
||||
static void gzo_close(void *stream)
|
||||
static int gzo_close(void *stream)
|
||||
{
|
||||
struct apk_gzip_ostream *gos = (struct apk_gzip_ostream *) stream;
|
||||
unsigned char buffer[1024];
|
||||
size_t have;
|
||||
int r;
|
||||
int r, rc = 0;
|
||||
|
||||
do {
|
||||
gos->zs.avail_out = sizeof(buffer);
|
||||
gos->zs.next_out = buffer;
|
||||
r = deflate(&gos->zs, Z_FINISH);
|
||||
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);
|
||||
gos->output->close(gos->output);
|
||||
r = gos->output->close(gos->output);
|
||||
if (r != 0)
|
||||
rc = r;
|
||||
|
||||
deflateEnd(&gos->zs);
|
||||
free(stream);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
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)
|
||||
os = apk_ostream_to_file(AT_FDCWD, ictx->output, 0644);
|
||||
os = apk_ostream_to_file(AT_FDCWD, ictx->output, NULL, 0644);
|
||||
else
|
||||
os = apk_ostream_to_fd(STDOUT_FILENO);
|
||||
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;
|
||||
|
||||
fis = malloc(sizeof(struct apk_fd_istream));
|
||||
if (fis == NULL)
|
||||
if (fis == NULL) {
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*fis = (struct apk_fd_istream) {
|
||||
.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_ostream os;
|
||||
int fd;
|
||||
int fd, rc;
|
||||
|
||||
const char *file, *tmpfile;
|
||||
int atfd;
|
||||
|
||||
size_t bytes;
|
||||
char buffer[1024];
|
||||
};
|
||||
|
@ -555,8 +561,10 @@ static ssize_t fdo_flush(struct apk_fd_ostream *fos)
|
|||
if (fos->bytes == 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;
|
||||
}
|
||||
|
||||
fos->bytes = 0;
|
||||
return 0;
|
||||
|
@ -572,8 +580,12 @@ static ssize_t fdo_write(void *stream, const void *ptr, size_t size)
|
|||
r = fdo_flush(fos);
|
||||
if (r != 0)
|
||||
return r;
|
||||
if (size >= sizeof(fos->buffer) / 2)
|
||||
return safe_write(fos->fd, ptr, size);
|
||||
if (size >= sizeof(fos->buffer) / 2) {
|
||||
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);
|
||||
|
@ -582,14 +594,28 @@ static ssize_t fdo_write(void *stream, const void *ptr, size_t size)
|
|||
return size;
|
||||
}
|
||||
|
||||
static void fdo_close(void *stream)
|
||||
static int fdo_close(void *stream)
|
||||
{
|
||||
struct apk_fd_ostream *fos =
|
||||
container_of(stream, struct apk_fd_ostream, os);
|
||||
int rc = fos->rc;
|
||||
|
||||
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);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
struct apk_ostream *apk_ostream_to_fd(int fd)
|
||||
|
@ -600,8 +626,10 @@ struct apk_ostream *apk_ostream_to_fd(int fd)
|
|||
return NULL;
|
||||
|
||||
fos = malloc(sizeof(struct apk_fd_ostream));
|
||||
if (fos == NULL)
|
||||
if (fos == NULL) {
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*fos = (struct apk_fd_ostream) {
|
||||
.os.write = fdo_write,
|
||||
|
@ -612,17 +640,32 @@ struct apk_ostream *apk_ostream_to_fd(int fd)
|
|||
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;
|
||||
|
||||
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)
|
||||
return NULL;
|
||||
|
||||
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 {
|
||||
|
@ -639,12 +682,13 @@ static ssize_t co_write(void *stream, const void *ptr, size_t size)
|
|||
return size;
|
||||
}
|
||||
|
||||
static void co_close(void *stream)
|
||||
static int co_close(void *stream)
|
||||
{
|
||||
struct apk_counter_ostream *cos =
|
||||
container_of(stream, struct apk_counter_ostream, os);
|
||||
|
||||
free(cos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct apk_ostream *apk_ostream_counter(off_t *counter)
|
||||
|
|
Loading…
Reference in New Issue