summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr.bin/rcs/rcs.c138
-rw-r--r--usr.bin/rcs/rcs.h4
2 files changed, 76 insertions, 66 deletions
diff --git a/usr.bin/rcs/rcs.c b/usr.bin/rcs/rcs.c
index 4b742e91a94..cfeff4dc281 100644
--- a/usr.bin/rcs/rcs.c
+++ b/usr.bin/rcs/rcs.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rcs.c,v 1.8 2006/05/08 16:56:40 xsa Exp $ */
+/* $OpenBSD: rcs.c,v 1.9 2006/05/11 07:34:26 xsa Exp $ */
/*
* Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
* All rights reserved.
@@ -214,6 +214,7 @@ int rcs_errno = RCS_ERR_NOERR;
char *timezone_flag = NULL;
int rcs_patch_lines(struct rcs_lines *, struct rcs_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 *);
@@ -352,28 +353,24 @@ rcs_close(RCSFILE *rfp)
*
* Write the contents of the RCS file handle <rfp> to disk in the file whose
* path is in <rf_path>.
- * Returns 0 on success, or -1 on failure.
*/
-int
+void
rcs_write(RCSFILE *rfp)
{
FILE *fp;
char buf[1024], numbuf[64], *fn;
- void *bp;
struct rcs_access *ap;
struct rcs_sym *symp;
struct rcs_branch *brp;
struct rcs_delta *rdp;
struct rcs_lock *lkp;
- ssize_t nread, nwritten;
size_t len;
- int fd, from_fd, to_fd, ret;
+ int fd, from_fd, to_fd;
from_fd = to_fd = fd = -1;
- ret = -1;
if (rfp->rf_flags & RCS_SYNCED)
- return (0);
+ return;
/* Write operations need the whole file parsed */
rcs_parse_deltatexts(rfp, NULL);
@@ -499,76 +496,89 @@ rcs_write(RCSFILE *rfp)
}
fputs("@\n", fp);
}
- fclose(fp);
+ (void)fclose(fp);
- /*
- * We try to use rename() to atomically put the new file in place.
- * If that fails, we try a copy.
- */
- if (rename(fn, rfp->rf_path) == -1) {
- if (errno == EXDEV) {
- /* rename() not supported so we have to copy. */
- if (chmod(rfp->rf_path, S_IWUSR) == -1 &&
- !(rfp->rf_flags & RCS_CREATE)) {
- errx(1, "chmod(%s, 0%o) failed",
- rfp->rf_path, S_IWUSR);
- }
+ if (rcs_movefile(fn, rfp->rf_path, rfp->rf_mode, rfp->rf_flags) == -1) {
+ (void)unlink(fn);
+ errx(1, "rcs_movefile failed");
+ }
- if ((from_fd = open(fn, O_RDONLY)) == -1) {
- warn("failed to open `%s'", rfp->rf_path);
- goto out;
- }
+ rfp->rf_flags |= RCS_SYNCED;
- if ((to_fd = open(rfp->rf_path,
- O_WRONLY|O_TRUNC|O_CREAT)) == -1) {
- warn("failed to open `%s'", fn);
- goto out;
- }
+ if (fn != NULL)
+ xfree(fn);
+}
- bp = xmalloc(MAXBSIZE);
- for (;;) {
- if ((nread = read(from_fd, bp, MAXBSIZE)) == 0)
- break;
- if (nread == -1)
- goto err;
- nwritten = write(to_fd, bp, (size_t)nread);
- if (nwritten == -1 || nwritten != nread)
- goto err;
- }
+/*
+ * 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;
+ int ret;
- if (nread < 0) {
-err: if (unlink(rfp->rf_path) == -1)
- warn("failed to unlink `%s'",
- rfp->rf_path);
- xfree(bp);
- goto out;
- }
- xfree(bp);
+ ret = -1;
- if (unlink(fn) == -1) {
- warn("failed to unlink `%s'", fn);
- goto out;
- }
- } else {
- warn("failed to access temp RCS output file");
- goto out;
+ if (rename(from, to) == 0) {
+ if (chmod(to, perm) == -1) {
+ warn("%s", to);
+ return (-1);
}
+ return (0);
+ } else if (errno != EXDEV) {
+ warn("failed to access temp RCS output file");
+ return (-1);
}
- if (chmod(rfp->rf_path, rfp->rf_mode) == -1) {
- warn("failed to chmod `%s'", rfp->rf_path);
- goto out;
+ if ((chmod(to, S_IWUSR) == -1) && !(to_flags & RCS_CREATE)) {
+ warnx("chmod(%s, 0%o) failed", to, S_IWUSR);
+ return (-1);
}
- rfp->rf_flags |= RCS_SYNCED;
+ /* different filesystem, have to copy the file */
+ if ((src = fopen(from, "r")) == NULL) {
+ warn("%s", from);
+ return (-1);
+ }
+ if ((dst = fopen(to, "w")) == NULL) {
+ warn("%s", to);
+ return (-1);
+ }
+ if (fchmod(fileno(dst), perm)) {
+ warn("%s", to);
+ (void)unlink(to);
+ return (-1);
+ }
+
+ buf = xmalloc(MAXBSIZE);
+ while ((nread = fread(buf, sizeof(char), MAXBSIZE, src)) != 0) {
+ if (ferror(src)) {
+ warnx("failed to read `%s'", from);
+ (void)unlink(to);
+ goto out;
+ }
+ nwritten = fwrite(buf, sizeof(char), nread, dst);
+ if (nwritten != nread) {
+ warnx("failed to write `%s'", to);
+ (void)unlink(to);
+ goto out;
+ }
+ }
ret = 0;
-out:
- (void)close(from_fd);
- (void)close(to_fd);
- if (fn != NULL)
- xfree(fn);
+ (void)fclose(src);
+ (void)fclose(dst);
+ (void)unlink(from);
+
+out:
+ xfree(buf);
return (ret);
}
diff --git a/usr.bin/rcs/rcs.h b/usr.bin/rcs/rcs.h
index adf7677bdc6..725bb40447d 100644
--- a/usr.bin/rcs/rcs.h
+++ b/usr.bin/rcs/rcs.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rcs.h,v 1.2 2006/04/26 21:55:22 joris Exp $ */
+/* $OpenBSD: rcs.h,v 1.3 2006/05/11 07:34:26 xsa Exp $ */
/*
* Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
* All rights reserved.
@@ -250,7 +250,7 @@ const char *rcs_state_get(RCSFILE *, RCSNUM *);
int rcs_state_check(const char *);
RCSNUM *rcs_tag_resolve(RCSFILE *, const char *);
const char *rcs_errstr(int);
-int rcs_write(RCSFILE *);
+void rcs_write(RCSFILE *);
int rcs_kflag_get(const char *);
void rcs_kflag_usage(void);