diff options
author | Otto Moerbeek <otto@cvs.openbsd.org> | 2007-02-01 20:36:22 +0000 |
---|---|---|
committer | Otto Moerbeek <otto@cvs.openbsd.org> | 2007-02-01 20:36:22 +0000 |
commit | fafdfab10d7ca58f82e423702d46609d8d73f37e (patch) | |
tree | 71ce08d0031f8ce9e2b907e74247dc6360632376 /usr.bin/cvs/rcs.c | |
parent | 41d09ad1c420c0dbd17d8c857e592cf24b3fdce3 (diff) |
When writing an rcs file, create the temp file next to the target
file and then rename. Avoids inter-filesystem copy and fixes a
potential rcs file truncation when the target fileystem becomes full.
While there, use fchmod instead of chmod. ok xsa@ joris@
Diffstat (limited to 'usr.bin/cvs/rcs.c')
-rw-r--r-- | usr.bin/cvs/rcs.c | 103 |
1 files changed, 19 insertions, 84 deletions
diff --git a/usr.bin/cvs/rcs.c b/usr.bin/cvs/rcs.c index 183df490b07..604771ed404 100644 --- a/usr.bin/cvs/rcs.c +++ b/usr.bin/cvs/rcs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rcs.c,v 1.206 2007/01/26 21:59:11 otto Exp $ */ +/* $OpenBSD: rcs.c,v 1.207 2007/02/01 20:36:21 otto Exp $ */ /* * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org> * All rights reserved. @@ -215,7 +215,6 @@ static const char *rcs_errstrs[] = { int rcs_errno = RCS_ERR_NOERR; int rcs_patch_lines(struct cvs_lines *, struct cvs_lines *); -static int rcs_movefile(char *, char *, mode_t, u_int); static void rcs_parse_init(RCSFILE *); static int rcs_parse_admin(RCSFILE *); static int rcs_parse_delta(RCSFILE *); @@ -361,16 +360,16 @@ void rcs_write(RCSFILE *rfp) { FILE *fp; - char buf[1024], numbuf[64], *fn; + char buf[1024], numbuf[64], *fn, tmpdir[MAXPATHLEN]; struct rcs_access *ap; struct rcs_sym *symp; struct rcs_branch *brp; struct rcs_delta *rdp; struct rcs_lock *lkp; size_t len; - int fd, from_fd, to_fd; + int fd, saved_errno; - from_fd = to_fd = fd = -1; + fd = -1; if (rfp->rf_flags & RCS_SYNCED) return; @@ -381,18 +380,17 @@ rcs_write(RCSFILE *rfp) /* Write operations need the whole file parsed */ rcs_parse_deltatexts(rfp, NULL); - (void)xasprintf(&fn, "%s/rcs.XXXXXXXXXX", cvs_tmpdir); + if (strlcpy(tmpdir, rfp->rf_path, sizeof(tmpdir)) >= sizeof(tmpdir)) + fatal("rcs_write: truncation"); + (void)xasprintf(&fn, "%s/rcs.XXXXXXXXXX", dirname(tmpdir)); if ((fd = mkstemp(fn)) == -1) fatal("%s", fn); - if ((fp = fdopen(fd, "w+")) == NULL) { - int saved_errno; - + if ((fp = fdopen(fd, "w")) == NULL) { saved_errno = errno; (void)unlink(fn); - errno = saved_errno; - fatal("%s", fn); + fatal("fdopen %s: %s", fn, strerror(saved_errno)); } if (rfp->rf_head != NULL) @@ -497,11 +495,19 @@ rcs_write(RCSFILE *rfp) } fputs("@\n", fp); } + if (fchmod(fd, rfp->rf_mode) == -1) { + saved_errno = errno; + (void)unlink(fn); + fatal("fchmod %s: %s", fn, strerror(saved_errno)); + } + (void)fclose(fp); - if (rcs_movefile(fn, rfp->rf_path, rfp->rf_mode, rfp->rf_flags) == -1) { + if (rename(fn, rfp->rf_path) == -1) { + saved_errno = errno; (void)unlink(fn); - fatal("rcs_movefile failed"); + fatal("rename(%s, %s): %s", fn, rfp->rf_path, + strerror(saved_errno)); } rfp->rf_flags |= RCS_SYNCED; @@ -511,77 +517,6 @@ rcs_write(RCSFILE *rfp) } /* - * rcs_movefile() - * - * Move a file using rename(2) if possible and copying if not. - * Returns 0 on success, -1 on failure. - */ -static int -rcs_movefile(char *from, char *to, mode_t perm, u_int to_flags) -{ - FILE *src, *dst; - size_t nread, nwritten; - char buf[MAXBSIZE]; - int ret; - - ret = -1; - - if (rename(from, to) == 0) { - if (chmod(to, perm) == -1) { - cvs_log(LP_ERRNO, "%s", to); - return (-1); - } - return (0); - } else if (errno != EXDEV) { - cvs_log(LP_NOTICE, "failed to access temp RCS output file"); - return (-1); - } - - if ((chmod(to, S_IWUSR) == -1) && !(to_flags & RCS_CREATE)) { - cvs_log(LP_ERR, "chmod(%s, 0%o) failed", to, S_IWUSR); - return (-1); - } - - /* different filesystem, have to copy the file */ - if ((src = fopen(from, "r")) == NULL) { - cvs_log(LP_ERRNO, "%s", from); - return (-1); - } - if ((dst = fopen(to, "w")) == NULL) { - cvs_log(LP_ERRNO, "%s", to); - return (-1); - } - if (fchmod(fileno(dst), perm)) { - cvs_log(LP_ERR, "%s", to); - (void)unlink(to); - return (-1); - } - - while ((nread = fread(buf, sizeof(char), MAXBSIZE, src)) != 0) { - if (ferror(src)) { - cvs_log(LP_ERRNO, "failed to read `%s'", from); - (void)unlink(to); - goto out; - } - nwritten = fwrite(buf, sizeof(char), nread, dst); - if (nwritten != nread) { - cvs_log(LP_ERRNO, "failed to write `%s'", to); - (void)unlink(to); - goto out; - } - } - - (void)unlink(from); - ret = 0; - -out: - (void)fclose(src); - (void)fclose(dst); - - return (ret); -} - -/* * rcs_head_get() * * Retrieve the revision number of the head revision for the RCS file <file>. |