summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTimo Teras <timo.teras@iki.fi>2009-08-12 11:05:09 +0300
committerTimo Teras <timo.teras@iki.fi>2009-08-12 11:05:09 +0300
commitdee6ffa492c2efee982dcd0b4724213317eceb37 (patch)
treeadd143a84e1679384f0101e86cc712d387387a89
parentbd9835a20ee6b191c844ebba0433e5d321c976f4 (diff)
downloadapk-tools-dee6ffa492c2efee982dcd0b4724213317eceb37.tar.bz2
apk-tools-dee6ffa492c2efee982dcd0b4724213317eceb37.tar.xz
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.
-rw-r--r--src/apk_io.h6
-rw-r--r--src/database.c62
-rw-r--r--src/gunzip.c13
-rw-r--r--src/index.c2
-rw-r--r--src/io.c68
5 files changed, 106 insertions, 45 deletions
diff --git a/src/apk_io.h b/src/apk_io.h
index 53b91b3..68f9925 100644
--- a/src/apk_io.h
+++ b/src/apk_io.h
@@ -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);
diff --git a/src/database.c b/src/database.c
index cafa47f..7b0900c 100644
--- a/src/database.c
+++ b/src/database.c
@@ -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);
-
- if (renameat(db->root_fd, "var/lib/apk/installed.new",
- db->root_fd, "var/lib/apk/installed") < 0)
- return -errno;
+ r = os->close(os);
+ if (r < 0)
+ return r;
- 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)
diff --git a/src/gunzip.c b/src/gunzip.c
index e5144a0..dd8d248 100644
--- a/src/gunzip.c
+++ b/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)
diff --git a/src/index.c b/src/index.c
index fbf1bcb..d485afd 100644
--- a/src/index.c
+++ b/src/index.c
@@ -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) {
diff --git a/src/io.c b/src/io.c
index 1b25355..40590a2 100644
--- a/src/io.c
+++ b/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)