summaryrefslogtreecommitdiff
path: root/src/io.c
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 /src/io.c
parentbd9835a20ee6b191c844ebba0433e5d321c976f4 (diff)
downloadapk-tools-dee6ffa492c2efee982dcd0b4724213317eceb37.tar.gz
apk-tools-dee6ffa492c2efee982dcd0b4724213317eceb37.tar.bz2
apk-tools-dee6ffa492c2efee982dcd0b4724213317eceb37.tar.xz
apk-tools-dee6ffa492c2efee982dcd0b4724213317eceb37.zip
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.
Diffstat (limited to 'src/io.c')
-rw-r--r--src/io.c68
1 files changed, 56 insertions, 12 deletions
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)