diff options
Diffstat (limited to 'contrib/cvs/src/lock.c')
-rw-r--r-- | contrib/cvs/src/lock.c | 185 |
1 files changed, 170 insertions, 15 deletions
diff --git a/contrib/cvs/src/lock.c b/contrib/cvs/src/lock.c index 1f2ccad..a0c0a34 100644 --- a/contrib/cvs/src/lock.c +++ b/contrib/cvs/src/lock.c @@ -8,6 +8,8 @@ * Set Lock * * Lock file support for CVS. + * + * $FreeBSD$ */ /* The node Concurrency in doc/cvs.texinfo has a brief introduction to @@ -73,6 +75,7 @@ unneeded complication although it presumably would be faster). */ #include "cvs.h" +#include <assert.h> struct lock { /* This is the directory in which we may have a lock named by the @@ -134,12 +137,161 @@ static List *lock_tree_list; static char *locked_dir; static List *locked_list; +/* LockDir from CVSROOT/config. */ +char *lock_dir; + +static char *lock_name PROTO ((char *repository, char *name)); + +/* Return a newly malloc'd string containing the name of the lock for the + repository REPOSITORY and the lock file name within that directory + NAME. Also create the directories in which to put the lock file + if needed (if we need to, could save system call(s) by doing + that only if the actual operation fails. But for now we'll keep + things simple). */ +static char * +lock_name (repository, name) + char *repository; + char *name; +{ + char *retval; + char *p; + char *q; + char *short_repos; + mode_t save_umask; + int saved_umask = 0; + + if (lock_dir == NULL) + { + /* This is the easy case. Because the lock files go directly + in the repository, no need to create directories or anything. */ + retval = xmalloc (strlen (repository) + strlen (name) + 10); + (void) sprintf (retval, "%s/%s", repository, name); + } + else + { + struct stat sb; + mode_t new_mode = 0; + + /* The interesting part of the repository is the part relative + to CVSROOT. */ + assert (CVSroot_directory != NULL); + assert (strncmp (repository, CVSroot_directory, + strlen (CVSroot_directory)) == 0); + short_repos = repository + strlen (CVSroot_directory); + assert (*short_repos++ == '/'); + + retval = xmalloc (strlen (lock_dir) + + strlen (short_repos) + + strlen (name) + + 10); + strcpy (retval, lock_dir); + q = retval + strlen (retval); + *q++ = '/'; + + strcpy (q, short_repos); + + /* In the common case, where the directory already exists, let's + keep it to one system call. */ + if (CVS_STAT (retval, &sb) < 0) + { + /* If we need to be creating more than one directory, we'll + get the existence_error here. */ + if (!existence_error (errno)) + error (1, errno, "cannot stat directory %s", retval); + } + else + { + if (S_ISDIR (sb.st_mode)) + goto created; + else + error (1, 0, "%s is not a directory", retval); + } + + /* Now add the directories one at a time, so we can create + them if needed. + + The idea behind the new_mode stuff is that the directory we + end up creating will inherit permissions from its parent + directory (we re-set new_mode with each EEXIST). CVSUMASK + isn't right, because typically the reason for LockDir is to + use a different set of permissions. We probably want to + inherit group ownership also (but we don't try to deal with + that, some systems do it for us either always or when g+s is on). + + We don't try to do anything about the permissions on the lock + files themselves. The permissions don't really matter so much + because the locks will generally be removed by the process + which created them. */ + + if (CVS_STAT (lock_dir, &sb) < 0) + error (1, errno, "cannot stat %s", lock_dir); + new_mode = sb.st_mode; + save_umask = umask (0000); + saved_umask = 1; + + p = short_repos; + while (1) + { + while (!ISDIRSEP (*p) && *p != '\0') + ++p; + if (ISDIRSEP (*p)) + { + strncpy (q, short_repos, p - short_repos); + q[p - short_repos] = '\0'; + if (!ISDIRSEP (q[p - short_repos - 1]) + && CVS_MKDIR (retval, new_mode) < 0) + { + int saved_errno = errno; + if (saved_errno != EEXIST) + error (1, errno, "cannot make directory %s", retval); + else + { + if (CVS_STAT (retval, &sb) < 0) + error (1, errno, "cannot stat %s", retval); + new_mode = sb.st_mode; + } + } + ++p; + } + else + { + strcpy (q, short_repos); + if (CVS_MKDIR (retval, new_mode) < 0 + && errno != EEXIST) + error (1, errno, "cannot make directory %s", retval); + goto created; + } + } + created:; + + strcat (retval, "/"); + strcat (retval, name); + + if (saved_umask) + { + assert (umask (save_umask) == 0000); + saved_umask = 0; + } + } + return retval; +} + /* * Clean up all outstanding locks */ void Lock_Cleanup () { + /* FIXME: error handling here is kind of bogus; we sometimes will call + error, which in turn can call us again. For the moment work around + this by refusing to reenter this function (this is a kludge). */ + /* FIXME-reentrancy: the workaround isn't reentrant. */ + static int in_lock_cleanup = 0; + + if (in_lock_cleanup) + return; + in_lock_cleanup = 1; + remove_locks (); dellist (&lock_tree_list); @@ -151,6 +303,7 @@ Lock_Cleanup () locked_dir = NULL; locked_list = NULL; } + in_lock_cleanup = 0; } /* @@ -199,8 +352,7 @@ lock_simple_remove (lock) existence_error here. */ if (readlock != NULL) { - tmp = xmalloc (strlen (lock->repository) + strlen (readlock) + 10); - (void) sprintf (tmp, "%s/%s", lock->repository, readlock); + tmp = lock_name (lock->repository, readlock); if ( CVS_UNLINK (tmp) < 0 && ! existence_error (errno)) error (0, errno, "failed to remove lock %s", tmp); free (tmp); @@ -212,8 +364,7 @@ lock_simple_remove (lock) existence_error here. */ if (writelock != NULL) { - tmp = xmalloc (strlen (lock->repository) + strlen (writelock) + 10); - (void) sprintf (tmp, "%s/%s", lock->repository, writelock); + tmp = lock_name (lock->repository, writelock); if ( CVS_UNLINK (tmp) < 0 && ! existence_error (errno)) error (0, errno, "failed to remove lock %s", tmp); free (tmp); @@ -221,8 +372,7 @@ lock_simple_remove (lock) if (lock->have_lckdir) { - tmp = xmalloc (strlen (lock->repository) + sizeof (CVSLCK) + 10); - (void) sprintf (tmp, "%s/%s", lock->repository, CVSLCK); + tmp = lock_name (lock->repository, CVSLCK); SIG_beginCrSect (); if (CVS_RMDIR (tmp) < 0) error (0, errno, "failed to remove lock dir %s", tmp); @@ -283,8 +433,7 @@ Reader_Lock (xrepository) } /* write a read-lock */ - tmp = xmalloc (strlen (xrepository) + strlen (readlock) + 10); - (void) sprintf (tmp, "%s/%s", xrepository, readlock); + tmp = lock_name (xrepository, readlock); if ((fp = CVS_FOPEN (tmp, "w+")) == NULL || fclose (fp) == EOF) { error (0, errno, "cannot create read lock in repository `%s'", @@ -437,8 +586,7 @@ write_lock (lock) } /* write the write-lock file */ - tmp = xmalloc (strlen (lock->repository) + strlen (writelock) + 10); - (void) sprintf (tmp, "%s/%s", lock->repository, writelock); + tmp = lock_name (lock->repository, writelock); if ((fp = CVS_FOPEN (tmp, "w+")) == NULL || fclose (fp) == EOF) { int xerrno = errno; @@ -582,8 +730,7 @@ set_lock (lock, will_wait) if (masterlock != NULL) free (masterlock); - masterlock = xmalloc (strlen (lock->repository) + sizeof (CVSLCK) + 10); - (void) sprintf (masterlock, "%s/%s", lock->repository, CVSLCK); + masterlock = lock_name (lock->repository, CVSLCK); /* * Note that it is up to the callers of set_lock() to arrange for signal @@ -680,13 +827,17 @@ lock_wait (repos) char *repos; { time_t now; + char *msg; (void) time (&now); - error (0, 0, "[%8.8s] waiting for %s's lock in %s", ctime (&now) + 11, - lockers_name, repos); + msg = xmalloc (100 + strlen (lockers_name) + strlen (repos)); + sprintf (msg, "[%8.8s] waiting for %s's lock in %s", ctime (&now) + 11, + lockers_name, repos); + error (0, 0, "%s", msg); /* Call cvs_flusherr to ensure that the user sees this message as soon as possible. */ cvs_flusherr (); + free (msg); (void) sleep (CVSLCKSLEEP); } @@ -698,12 +849,16 @@ lock_obtained (repos) char *repos; { time_t now; + char *msg; (void) time (&now); - error (0, 0, "[%8.8s] obtained lock in %s", ctime (&now) + 11, repos); + msg = xmalloc (100 + strlen (repos)); + sprintf (msg, "[%8.8s] obtained lock in %s", ctime (&now) + 11, repos); + error (0, 0, "%s", msg); /* Call cvs_flusherr to ensure that the user sees this message as soon as possible. */ cvs_flusherr (); + free (msg); } static int lock_filesdoneproc PROTO ((void *callerdat, int err, |