>Submitter-Id: net
>Originator: [EMAIL PROTECTED]
>Organization: MasterLink, INC
net
>Confidential: no
>Synopsis: CVS hoses self in unexpected sticky directory
>Severity: serious
>Priority: medium
>Category: cvs
>Class: change-request
>Release: cvs-1.10
>Environment:
linux, should happen on all flavors/hw architectures
System: Linux monster 2.2.13 #19 SMP Thu May 18 21:00:09 EDT 2000 i686 unknown
Architecture: i686
>Description:
If a cvs directory is sticky, and commits fail because of it, then
there will be a temporary file left that will prevent future commits
of that file.
>How-To-Repeat:
1) Create a repository/project
2) Make the repository world readable/writable, and set the sticky bit
3) add some files as the owner of the directory
4) do a checkout as somebody else
5) change a file in the checked out copy
6) commit
// This will fail, because in a sticky directory, user 1 is not allowed
// to delete files owned by user 2, unless user 1 is the owner of the
// directory
7) change the same file in a copy checked out as the owner
8) commit
// This will fail, because the first failure left a lockfile behind
>Fix:
// Here is a patch that will correct the problem:
diff -r -u cvs-1.10/src/cvs.h cvs-1.10.hacked/src/cvs.h
--- cvs-1.10/src/cvs.h Sun Jul 26 22:54:11 1998
+++ cvs-1.10.hacked/src/cvs.h Wed Jun 28 06:10:32 2000
@@ -532,6 +532,7 @@
void make_directory PROTO((const char *name));
extern int mkdir_if_needed PROTO ((char *name));
void rename_file PROTO((const char *from, const char *to));
+void rename_or_delete_file PROTO((const char *from, const char *to));
/* Expand wildcards in each element of (ARGC,ARGV). This is according to the
files which exist in the current directory, and accordingly to OS-specific
conventions regarding wildcard syntax. It might be desirable to change the
diff -r -u cvs-1.10/src/filesubr.c cvs-1.10.hacked/src/filesubr.c
--- cvs-1.10/src/filesubr.c Mon May 11 14:19:25 1998
+++ cvs-1.10.hacked/src/filesubr.c Wed Jun 28 06:16:35 2000
@@ -414,6 +414,34 @@
error (1, errno, "cannot rename file %s to %s", from, to);
}
+/*
+ * This is the same as rename file, but it deltes the file it is trying
+ * to rename on failure. Since rename_file above exits on failure, there
+ * isn't any place above to catch the exception and delete the (now stale)
+ * lockfile
+ */
+void
+rename_or_delete_file (from, to)
+ const char *from;
+ const char *to;
+{
+ if (trace)
+#ifdef SERVER_SUPPORT
+ (void) fprintf (stderr, "%c-> rename(%s,%s)\n",
+ (server_active) ? 'S' : ' ', from, to);
+#else
+ (void) fprintf (stderr, "-> rename(%s,%s)\n", from, to);
+#endif
+ if (noexec)
+ return;
+
+ if (rename (from, to) < 0) {
+ int save_errno = errno;
+ unlink(from);
+ error (1, save_errno, "cannot rename file %s to %s", from, to);
+ };
+}
+
/*
* unlink a file, if possible.
*/
diff -r -u cvs-1.10/src/rcs.c cvs-1.10.hacked/src/rcs.c
--- cvs-1.10/src/rcs.c Thu Aug 6 20:38:26 1998
+++ cvs-1.10.hacked/src/rcs.c Wed Jun 28 06:10:05 2000
@@ -8416,7 +8416,7 @@
if (fclose (fp) == EOF)
error (1, errno, "error closing lock file %s", lockfile);
- rename_file (lockfile, rcsfile);
+ rename_or_delete_file (lockfile, rcsfile);
free (lockfile);
}