diff options
author | Jeremy Kerr <jk@ozlabs.org> | 2013-08-08 15:25:24 +0800 |
---|---|---|
committer | Jeremy Kerr <jk@ozlabs.org> | 2013-08-08 16:30:00 +0800 |
commit | 6557f07325409d769f414035cca05a563418e729 (patch) | |
tree | e817fabedfd85b0584089fe2f476189d7ccdc41d | |
parent | a70807730ef59efc4116556ecabe1b9f70ce605b (diff) | |
download | petitboot-6557f07325409d769f414035cca05a563418e729.zip petitboot-6557f07325409d769f414035cca05a563418e729.tar.gz |
discover/file: Add replace_file()
Add a function to atomically replace a file.
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
-rw-r--r-- | discover/file.c | 43 | ||||
-rw-r--r-- | discover/file.h | 1 |
2 files changed, 44 insertions, 0 deletions
diff --git a/discover/file.c b/discover/file.c index 269421c..1ebfe43 100644 --- a/discover/file.c +++ b/discover/file.c @@ -17,6 +17,8 @@ #include <fcntl.h> #include <unistd.h> +#include <stdlib.h> +#include <errno.h> #include <sys/stat.h> #include <sys/types.h> @@ -75,3 +77,44 @@ err_close: close(fd); return -1; } + +static int write_fd(int fd, char *buf, int len) +{ + int i, rc; + + for (i = 0; i < len; i += rc) { + rc = write(fd, buf + i, len - i); + if (rc < 0 && errno != -EINTR) + return rc; + } + + return 0; +} + +int replace_file(const char *filename, char *buf, int len) +{ + char *tempfile; + mode_t oldmask; + int rc, fd; + + tempfile = talloc_asprintf(NULL, "%s.XXXXXX", filename); + + oldmask = umask(0644); + fd = mkstemp(tempfile); + umask(oldmask); + if (fd < 0) { + free(tempfile); + return fd; + } + + rc = write_fd(fd, buf, len); + if (rc) { + unlink(tempfile); + } else { + rc = rename(tempfile, filename); + } + + free(tempfile); + close(fd); + return rc; +} diff --git a/discover/file.h b/discover/file.h index 1997eca..8aa7d3c 100644 --- a/discover/file.h +++ b/discover/file.h @@ -18,6 +18,7 @@ #define FILE_H int read_file(void *ctx, const char *filename, char **bufp, int *lenp); +int replace_file(const char *filename, char *buf, int len); #endif /* FILE_H */ |