diff options
author | obrien <obrien@FreeBSD.org> | 2008-01-13 06:08:17 +0000 |
---|---|---|
committer | obrien <obrien@FreeBSD.org> | 2008-01-13 06:08:17 +0000 |
commit | 1d7ee3ab516b5d20bec63b1f10cad63819593d53 (patch) | |
tree | 12de98f3e61b620a2efa64b05ab0420ebb7d06a7 /contrib/cvs/src | |
parent | 31b70a95c696d341a3ffc59a0df77323648db0f7 (diff) | |
download | FreeBSD-src-1d7ee3ab516b5d20bec63b1f10cad63819593d53.zip FreeBSD-src-1d7ee3ab516b5d20bec63b1f10cad63819593d53.tar.gz |
Merge rev 1.3 (catch write-lock attempts immediately if running in
read-only mode) & rev 1.2 (check out from read-only repository support)
into version 1.11.22.
Diffstat (limited to 'contrib/cvs/src')
-rw-r--r-- | contrib/cvs/src/lock.c | 224 |
1 files changed, 182 insertions, 42 deletions
diff --git a/contrib/cvs/src/lock.c b/contrib/cvs/src/lock.c index 36cbf7d..a407dac 100644 --- a/contrib/cvs/src/lock.c +++ b/contrib/cvs/src/lock.c @@ -1,6 +1,11 @@ /* - * Copyright (c) 1992, Brian Berliner and Jeff Polk - * Copyright (c) 1989-1992, Brian Berliner + * Copyright (C) 1986-2005 The Free Software Foundation, Inc. + * + * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, + * and others. + * + * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk + * Portions Copyright (C) 1989-1992, Brian Berliner * * You may distribute under the terms of the GNU General Public License as * specified in the README file that comes with the CVS source distribution. @@ -87,8 +92,17 @@ struct lock { case of writelocks, it is just a pointer to the storage allocated for the ->key field. */ char *repository; - /* Do we have a lock named CVSLCK? */ - int have_lckdir; + + /* The name of the master lock dir. Usually CVSLCK. */ + const char *lockdirname; + + /* The full path to the lock dir, if we are currently holding it. + * + * This will be LOCKDIRNAME catted onto REPOSITORY. We waste a little + * space by storing it, but save a later malloc/free. + */ + char *lockdir; + /* Note there is no way of knowing whether the readlock and writelock exist. The code which sets the locks doesn't use SIG_beginCrSect to set a flag like we do for CVSLCK. */ @@ -117,7 +131,6 @@ static char *readlock; static char *writelock; /* Malloc'd array specifying the name of a CVSLCK file (absolute pathname). Will always be non-NULL in the cases where it is used. */ -static char *masterlock; static List *locklist; #define L_OK 0 /* success */ @@ -126,7 +139,10 @@ static List *locklist; /* This is the (single) readlock which is set by Reader_Lock. The repository field is NULL if there is no such lock. */ -static struct lock global_readlock; +static struct lock global_readlock = {NULL, CVSLCK, NULL}; + +static struct lock global_history_lock = {NULL, CVSHISTORYLCK, NULL}; +static struct lock global_val_tags_lock = {NULL, CVSVALTAGSLCK, NULL}; /* List of locks set by lock_tree_for_write. This is redundant with locklist, sort of. */ @@ -142,7 +158,7 @@ static List *locked_list; /* LockDir from CVSROOT/config. */ char *lock_dir; -static char *lock_name PROTO ((char *repository, char *name)); +static char *lock_name PROTO ((const char *repository, const 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 @@ -152,13 +168,13 @@ static char *lock_name PROTO ((char *repository, char *name)); things simple). */ static char * lock_name (repository, name) - char *repository; - char *name; + const char *repository; + const char *name; { char *retval; - char *p; + const char *p; char *q; - char *short_repos; + const char *short_repos; mode_t save_umask; int saved_umask = 0; @@ -313,6 +329,10 @@ Lock_Cleanup () locked_dir = NULL; locked_list = NULL; } + + if (global_history_lock.repository) clear_history_lock (); + if (global_val_tags_lock.repository) clear_val_tags_lock (); + in_lock_cleanup = 0; } @@ -349,6 +369,8 @@ unlock_proc (p, closure) return (0); } + + /* Remove the lock files. */ static void lock_simple_remove (lock) @@ -363,7 +385,7 @@ lock_simple_remove (lock) if (readlock != NULL) { tmp = lock_name (lock->repository, readlock); - if ( CVS_UNLINK (tmp) < 0 && ! existence_error (errno)) + if (CVS_UNLINK (tmp) < 0 && ! existence_error (errno)) error (0, errno, "failed to remove lock %s", tmp); free (tmp); } @@ -375,21 +397,12 @@ lock_simple_remove (lock) if (writelock != NULL) { tmp = lock_name (lock->repository, writelock); - if ( CVS_UNLINK (tmp) < 0 && ! existence_error (errno)) + if (CVS_UNLINK (tmp) < 0 && ! existence_error (errno)) error (0, errno, "failed to remove lock %s", tmp); free (tmp); } - if (lock->have_lckdir) - { - tmp = lock_name (lock->repository, CVSLCK); - SIG_beginCrSect (); - if (CVS_RMDIR (tmp) < 0) - error (0, errno, "failed to remove lock dir %s", tmp); - lock->have_lckdir = 0; - SIG_endCrSect (); - free (tmp); - } + clear_lock (lock); } @@ -662,6 +675,9 @@ readers_exist (repository) #endif lockdir = lock_name (repository, ""); + + assert (lockdir != NULL); + lockdir[strlen (lockdir) - 1] = '\0'; /* remove trailing slash */ do { @@ -768,13 +784,13 @@ set_lock (lock, will_wait) long us; struct stat sb; mode_t omask; + char *masterlock; + int status; #ifdef CVS_FUDGELOCKS time_t now; #endif - if (masterlock != NULL) - free (masterlock); - masterlock = lock_name (lock->repository, CVSLCK); + masterlock = lock_name (lock->repository, lock->lockdirname); /* * Note that it is up to the callers of set_lock() to arrange for signal @@ -783,33 +799,33 @@ set_lock (lock, will_wait) */ waited = 0; us = 1; - lock->have_lckdir = 0; for (;;) { - int status = -1; + status = -1; omask = umask (cvsumask); SIG_beginCrSect (); if (CVS_MKDIR (masterlock, 0777) == 0) { - lock->have_lckdir = 1; + lock->lockdir = masterlock; SIG_endCrSect (); status = L_OK; if (waited) lock_obtained (lock->repository); - goto out; + goto after_sig_unblock; } SIG_endCrSect (); - out: + after_sig_unblock: (void) umask (omask); if (status != -1) - return status; + goto done; if (errno != EEXIST) { error (0, errno, "failed to create lock directory for `%s' (%s)", lock->repository, masterlock); - return (L_ERROR); + status = L_ERROR; + goto done; } /* Find out who owns the lock. If the lock directory is @@ -821,7 +837,8 @@ set_lock (lock, will_wait) continue; error (0, errno, "couldn't stat lock directory `%s'", masterlock); - return (L_ERROR); + status = L_ERROR; + goto done; } #ifdef CVS_FUDGELOCKS @@ -843,7 +860,10 @@ set_lock (lock, will_wait) /* if he wasn't willing to wait, return an error */ if (!will_wait) - return (L_LOCKED); + { + status = L_LOCKED; + goto done; + } /* if possible, try a very short sleep without a message */ if (!waited && us < 1000) @@ -874,23 +894,45 @@ set_lock (lock, will_wait) lock_wait (lock->repository); waited = 1; } +done: + if (!lock->lockdir) free (masterlock); + return status; } + + /* - * Clear master lock. We don't have to recompute the lock name since - * clear_lock is never called except after a successful set_lock(). + * Clear master lock. + * + * INPUTS + * lock The lock information. + * + * OUTPUTS + * Sets LOCK->lockdir to NULL after removing the directory it names and + * freeing the storage. + * + * ASSUMPTIONS + * If we own the master lock directory, its name is stored in LOCK->lockdir. + * We may free LOCK->lockdir. + * */ static void clear_lock (lock) struct lock *lock; { SIG_beginCrSect (); - if (CVS_RMDIR (masterlock) < 0) - error (0, errno, "failed to remove lock dir `%s'", masterlock); - lock->have_lckdir = 0; + if (lock->lockdir) + { + if (CVS_RMDIR (lock->lockdir) < 0) + error (0, errno, "failed to remove lock dir `%s'", lock->lockdir); + free (lock->lockdir); + lock->lockdir = NULL; + } SIG_endCrSect (); } + + /* * Print out a message that the lock is still held, then sleep a while. */ @@ -965,7 +1007,8 @@ lock_filesdoneproc (callerdat, err, repository, update_dir, entries) p->key = xstrdup (repository); p->data = xmalloc (sizeof (struct lock)); ((struct lock *)p->data)->repository = p->key; - ((struct lock *)p->data)->have_lckdir = 0; + ((struct lock *)p->data)->lockdirname = CVSLCK; + ((struct lock *)p->data)->lockdir = NULL; /* FIXME-KRP: this error condition should not simply be passed by. */ if (p->key == NULL || addnode (lock_tree_list, p) != 0) @@ -1018,9 +1061,106 @@ lock_dir_for_write (repository) node->key = xstrdup (repository); node->data = xmalloc (sizeof (struct lock)); ((struct lock *)node->data)->repository = node->key; - ((struct lock *)node->data)->have_lckdir = 0; + ((struct lock *)node->data)->lockdirname = CVSLCK; + ((struct lock *)node->data)->lockdir = NULL; (void) addnode (locked_list, node); Writer_Lock (locked_list); } } + + + +/* This is the internal implementation behind history_lock & val_tags_lock. It + * gets a write lock for the history or val-tags file. + * + * RETURNS + * true, on success + * false, on error + */ +static int internal_lock PROTO ((struct lock *lock, const char *xrepository)); +static int +internal_lock (lock, xrepository) + struct lock *lock; + const char *xrepository; +{ + /* remember what we're locking (for Lock_Cleanup) */ + assert (!lock->repository); + lock->repository = xmalloc (strlen (xrepository) + sizeof (CVSROOTADM) + 2); + sprintf (lock->repository, "%s/%s", xrepository, CVSROOTADM); + + /* get the lock dir for our own */ + if (set_lock (lock, 1) != L_OK) + { + if (!really_quiet) + error (0, 0, "failed to obtain history lock in repository `%s'", + xrepository); + + return 0; + } + + return 1; +} + + + +/* This is the internal implementation behind history_lock & val_tags_lock. It + * removes the write lock for the history or val-tags file, when it exists. + */ +static void internal_clear_lock PROTO((struct lock *lock)); +static void +internal_clear_lock (lock) + struct lock *lock; +{ + SIG_beginCrSect (); + if (lock->repository) + { + free (lock->repository); + lock->repository = NULL; + } + SIG_endCrSect (); + + clear_lock (lock); +} + + + +/* Lock the CVSROOT/history file for write. + */ +int +history_lock (xrepository) + const char *xrepository; +{ + return internal_lock (&global_history_lock, xrepository); +} + + + +/* Remove the CVSROOT/history lock, if it exists. + */ +void +clear_history_lock () +{ + internal_clear_lock (&global_history_lock); +} + + + +/* Lock the CVSROOT/val-tags file for write. + */ +int +val_tags_lock (xrepository) + const char *xrepository; +{ + return internal_lock (&global_val_tags_lock, xrepository); +} + + + +/* Remove the CVSROOT/val-tags lock, if it exists. + */ +void +clear_val_tags_lock () +{ + internal_clear_lock (&global_val_tags_lock); +} |