diff options
-rw-r--r-- | usr.bin/cvs/edit.c | 12 | ||||
-rw-r--r-- | usr.bin/cvs/file.c | 66 | ||||
-rw-r--r-- | usr.bin/cvs/file.h | 3 |
3 files changed, 77 insertions, 4 deletions
diff --git a/usr.bin/cvs/edit.c b/usr.bin/cvs/edit.c index b745509e20d..189d688b70d 100644 --- a/usr.bin/cvs/edit.c +++ b/usr.bin/cvs/edit.c @@ -1,4 +1,4 @@ -/* $OpenBSD: edit.c,v 1.16 2007/01/03 09:49:37 xsa Exp $ */ +/* $OpenBSD: edit.c,v 1.17 2007/01/05 07:13:49 xsa Exp $ */ /* * Copyright (c) 2006, 2007 Xavier Santolaria <xsa@openbsd.org> * @@ -177,7 +177,15 @@ cvs_unedit_local(struct cvs_file *cf) return; } - /* XXX: compare cf->file_path and bfpath */ + if (cvs_file_cmp(cf->file_path, bfpath) != 0) { + cvs_printf("%s has been modified; revert changes? ", + cf->file_name); + + if (cvs_yesno() == -1) { + xfree(bfpath); + return; + } + } cvs_rename(bfpath, cf->file_path); xfree(bfpath); diff --git a/usr.bin/cvs/file.c b/usr.bin/cvs/file.c index bf3f5c999fe..6e8f2773eb0 100644 --- a/usr.bin/cvs/file.c +++ b/usr.bin/cvs/file.c @@ -1,4 +1,4 @@ -/* $OpenBSD: file.c,v 1.163 2006/10/25 20:52:34 moritz Exp $ */ +/* $OpenBSD: file.c,v 1.164 2007/01/05 07:13:49 xsa Exp $ */ /* * Copyright (c) 2006 Joris Vink <joris@openbsd.org> * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org> @@ -27,6 +27,8 @@ #include "includes.h" +#include <sys/mman.h> + #include "cvs.h" #include "file.h" #include "log.h" @@ -847,3 +849,65 @@ cvs_file_cmpname(const char *name1, const char *name2) return (cvs_nocase == 0) ? (strcmp(name1, name2)) : (strcasecmp(name1, name2)); } + +int +cvs_file_cmp(const char *file1, const char *file2) +{ + struct stat stb1, stb2; + int fd1, fd2, ret; + + ret = 0; + + if ((fd1 = open(file1, O_RDONLY|O_NOFOLLOW, 0)) == -1) + fatal("cvs_file_cmp: open: `%s': %s", file1, strerror(errno)); + if ((fd2 = open(file2, O_RDONLY|O_NOFOLLOW, 0)) == -1) + fatal("cvs_file_cmp: open: `%s': %s", file2, strerror(errno)); + + if (fstat(fd1, &stb1) == -1) + fatal("cvs_file_cmp: `%s': %s", file1, strerror(errno)); + if (fstat(fd2, &stb2) == -1) + fatal("cvs_file_cmp: `%s': %s", file2, strerror(errno)); + + if (stb1.st_size != stb2.st_size || + (stb1.st_mode & S_IFMT) != (stb2.st_mode & S_IFMT)) { + ret = 1; + goto out; + } + + if (S_ISBLK(stb1.st_mode) || S_ISCHR(stb1.st_mode)) { + if (stb1.st_rdev != stb2.st_rdev) + ret = 1; + goto out; + } + + if (S_ISREG(stb1.st_mode)) { + void *p1, *p2; + + if (stb1.st_size > SIZE_MAX) { + ret = 1; + goto out; + } + + if ((p1 = mmap(NULL, stb1.st_size, PROT_READ, + MAP_FILE, fd1, (off_t)0)) == MAP_FAILED) + fatal("cvs_file_cmp: mmap failed"); + + if ((p2 = mmap(NULL, stb1.st_size, PROT_READ, + MAP_FILE, fd2, (off_t)0)) == MAP_FAILED) + fatal("cvs_file_cmp: mmap failed"); + + madvise(p1, stb1.st_size, MADV_SEQUENTIAL); + madvise(p2, stb1.st_size, MADV_SEQUENTIAL); + + ret = memcmp(p1, p2, stb1.st_size); + + (void)munmap(p1, stb1.st_size); + (void)munmap(p2, stb1.st_size); + } + +out: + (void)close(fd1); + (void)close(fd2); + + return (ret); +} diff --git a/usr.bin/cvs/file.h b/usr.bin/cvs/file.h index 00f5854de27..bb8de7b33dd 100644 --- a/usr.bin/cvs/file.h +++ b/usr.bin/cvs/file.h @@ -1,4 +1,4 @@ -/* $OpenBSD: file.h,v 1.37 2006/05/30 21:32:52 joris Exp $ */ +/* $OpenBSD: file.h,v 1.38 2007/01/05 07:13:49 xsa Exp $ */ /* * Copyright (c) 2006 Joris Vink <joris@openbsd.org> * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org> @@ -103,6 +103,7 @@ void cvs_file_freelist(struct cvs_flisthead *); struct cvs_filelist *cvs_file_get(const char *, struct cvs_flisthead *); int cvs_file_chkign(const char *); +int cvs_file_cmp(const char *, const char *); struct cvs_file *cvs_file_get_cf(const char *, const char *, int, int); |