diff options
author | Rob Austein <sra@hactrn.net> | 2011-06-12 01:33:50 +0000 |
---|---|---|
committer | Rob Austein <sra@hactrn.net> | 2011-06-12 01:33:50 +0000 |
commit | 8cead866711295ede483b5b7e4f7a57c6189f6d9 (patch) | |
tree | f422e2e79bcefab631e669462c4d93bdb997120f | |
parent | e212f7ab3f0b38e16e280301937d48506fe37b7f (diff) |
Preserve timestamps when copying files.
svn path=/rcynic-ng/rcynic.c; revision=3864
-rw-r--r-- | rcynic-ng/rcynic.c | 74 | ||||
-rw-r--r-- | rcynic/rcynic.c | 24 |
2 files changed, 63 insertions, 35 deletions
diff --git a/rcynic-ng/rcynic.c b/rcynic-ng/rcynic.c index 11894248..23db139f 100644 --- a/rcynic-ng/rcynic.c +++ b/rcynic-ng/rcynic.c @@ -59,6 +59,7 @@ #include <limits.h> #include <fcntl.h> #include <signal.h> +#include <utime.h> #define SYSLOG_NAMES /* defines CODE prioritynames[], facilitynames[] */ #include <syslog.h> @@ -941,12 +942,23 @@ static void reject(const rcynic_ctx_t *rc, } /** - * Copy a file + * Copy or link a file, as the case may be. */ -static int cp(const path_t *source, const path_t *target) +static int cp_ln(const rcynic_ctx_t *rc, const path_t *source, const path_t *target) { + struct stat statbuf; + struct utimbuf utimebuf; FILE *in = NULL, *out = NULL; - int c, ret = 0; + int c, ok = 0; + + if (rc->use_links) { + (void) unlink(target->s); + ok = link(source->s, target->s) == 0; + if (!ok) + logmsg(rc, log_sys_err, "Couldn't link %s to %s: %s", + source->s, target->s, strerror(errno)); + return ok; + } if ((in = fopen(source->s, "rb")) == NULL || (out = fopen(target->s, "wb")) == NULL) @@ -956,31 +968,36 @@ static int cp(const path_t *source, const path_t *target) if (putc(c, out) == EOF) goto done; - ret = 1; + ok = 1; done: - ret &= !(in != NULL && fclose(in) == EOF); - ret &= !(out != NULL && fclose(out) == EOF); - return ret; -} + ok &= !(in != NULL && fclose(in) == EOF); + ok &= !(out != NULL && fclose(out) == EOF); -/** - * Link a file - */ -static int ln(const path_t *source, const path_t *target) -{ - unlink(target->s); - return link(source->s, target->s) == 0; + if (!ok) { + logmsg(rc, log_sys_err, "Couldn't copy %s to %s: %s", + source->s, target->s, strerror(errno)); + return ok; + } + + /* + * Perserve the file modification time to allow for detection of + * changed objects in the authenticated directory. Failure to reset + * the times is not optimal, but is also not critical, thus no + * failure return. + */ + if (stat(source->s, &statbuf) < 0 || + (utimebuf.actime = statbuf.st_atime, + utimebuf.modtime = statbuf.st_mtime, + utime(target->s, &utimebuf) < 0)) + logmsg(rc, log_sys_err, "Couldn't copy inode timestamp from %s to %s: %s", + source->s, target->s, strerror(errno)); + + return ok; } /** - * Install an object. It'd be nice if we could just use link(), but - * that would require us to trust rsync never to do anything bad. For - * now we just copy in the simplest way possible. Come back to this - * if profiling shows a hotspot here. - * - * Well, ok, profiling didn't show an issue, but inode exhaustion did. - * So we now make copy vs link a configuration choice. + * Install an object. */ static int install_object(const rcynic_ctx_t *rc, const uri_t *uri, @@ -998,18 +1015,15 @@ static int install_object(const rcynic_ctx_t *rc, return 0; } - if (rc->use_links ? !ln(source, &target) : !cp(source, &target)) { - logmsg(rc, log_sys_err, "Couldn't %s %s to %s", - (rc->use_links ? "link" : "copy"), source->s, target.s); + if (!cp_ln(rc, source, &target)) return 0; - } log_validation_status(rc, uri, validation_ok); logmsg(rc, log_telemetry, "Accepted %s", uri->s); return 1; } /** - * Check str for a trailing suffix. + * Check str for a suffix. */ static int endswith(const char *str, const char *suffix) { @@ -3929,12 +3943,8 @@ int main(int argc, char *argv[]) logmsg(&rc, log_telemetry, "Copying trust anchor %s to %s", path1.s, path2.s); - if (!mkdir_maybe(&rc, &path2) || - !(rc.use_links ? ln(&path1, &path2) : cp(&path1, &path2))) { - logmsg(&rc, log_sys_err, "Couldn't %s trust anchor %s", - (rc.use_links ? "link" : "copy"), path1.s); + if (!mkdir_maybe(&rc, &path2) || !cp_ln(&rc, &path1, &path2)) goto done; - } if ((wsk = walk_ctx_stack_new()) == NULL) { logmsg(&rc, log_sys_err, "Couldn't allocate walk context stack"); diff --git a/rcynic/rcynic.c b/rcynic/rcynic.c index 84110c02..9400e6b7 100644 --- a/rcynic/rcynic.c +++ b/rcynic/rcynic.c @@ -59,6 +59,7 @@ #include <limits.h> #include <fcntl.h> #include <signal.h> +#include <utime.h> #define SYSLOG_NAMES /* defines CODE prioritynames[], facilitynames[] */ #include <syslog.h> @@ -1065,8 +1066,10 @@ static void reject(const rcynic_ctx_t *rc, /** * Copy a file */ -static int cp(const char *source, const char *target) +static int cp(const rcynic_ctx_t *rc, const char *source, const char *target) { + struct stat statbuf; + struct utimbuf utimebuf; FILE *in = NULL, *out = NULL; int c, ret = 0; @@ -1083,6 +1086,21 @@ static int cp(const char *source, const char *target) done: ret &= !(in != NULL && fclose(in) == EOF); ret &= !(out != NULL && fclose(out) == EOF); + + /* + * Perserve the file modification time to allow for detection of + * changed objects in the authenticated directory. Failure to reset + * the times is not optimal, but is also not critical, thus no + * failure return. Errors are reported with log_sys_err because + * there is no log type for warnings. + */ + if (ret && (stat(source, &statbuf) < 0 || + (utimebuf.actime = statbuf.st_atime, + utimebuf.modtime = statbuf.st_mtime, + utime(target, &utimebuf) < 0))) + logmsg(rc, log_sys_err, "Couldn't copy inode timestamp from %s to %s: %s", + source, target, strerror(errno)); + return ret; } @@ -1120,7 +1138,7 @@ static int install_object(const rcynic_ctx_t *rc, return 0; } - if (rc->use_links ? !ln(source, target) : !cp(source, target)) { + if (rc->use_links ? !ln(source, target) : !cp(rc, source, target)) { logmsg(rc, log_sys_err, "Couldn't %s %s to %s", (rc->use_links ? "link" : "copy"), source, target); return 0; @@ -3545,7 +3563,7 @@ int main(int argc, char *argv[]) logmsg(&rc, log_telemetry, "Copying trust anchor %s to %s", path1, path2); if (!mkdir_maybe(&rc, path2) || - !(rc.use_links ? ln(path1, path2) : cp(path1, path2))) { + !(rc.use_links ? ln(path1, path2) : cp(&rc, path1, path2))) { logmsg(&rc, log_sys_err, "Couldn't %s trust anchor %s", (rc.use_links ? "link" : "copy"), path1); goto done; |