A CVS repository is composed of the special CVSROOT administrative directory and any project directories you create. All the CVS administrative files and configuration files are kept in CVSROOT.
The project directories contain the project's files and subdirectories. The project's files are stored in RCS format and have a ,v file suffix.
Any project directory or subdirectory may contain Attic or CVS directories. An Attic subdirectory stores any file from the directory it's part of that doesn't exist on the trunk (the main development line for the file). The Attic directory is explained in Chapter 3. A CVS subdirectory stores metadata for the files in its directory.
The server also stores files in a temporary directory set by either the TMPDIR environment variable or the -T command-line option. These files are under a directory called cvs-serverPID, where PID is the process ID of the server. If the server is shut down and unable to clean up after itself, the files may be left in place. They can be removed safely if there is no CVS process running with the relevant process ID.
The only file stored in the CVS subdirectories in a repository is fileattr, which lists the file attributes of the files in the parent directory. The file attributes are settings for the cvs watch commands. In later versions of CVS, the fileattr file may be used for other attributes or the CVS subdirectory may be used for other files.
The format for fileattr is one line per attribute, each line containing information as follows:
entry-type filename (tab) attribute-name = attribute-value [;attribute-name = attribute-value...]
Attribute names starting with _ are reserved for CVS. Future versions of CVS may allow user-defined attributes. In the current version of CVS (version 1.11.5) and earlier, user-defined attributes are not allowed.
The F entry type designates that a line contains attributes for a file. The D entry type with no filename designates that the line contains default attributes for all files in the directory that includes the CVS subdirectory.
These are the supported attributes:
Indicates that the file is being watched and should be checked out read-only.
Lists the users watching the file. The value is in the form:
watcher > type [, watcher > type...]
watcher is a username; type is edit, unedit, commit, or some combination of those keywords, separated by + symbols. The tedit, tunedit, and tcommit types refer to the temporary watches created by the cvs edit command.
Lists the users editing the file. The value is in the form:
editor > value [, editor > value...]
editor is a username and value is time+hostname+pathname, where time indicates when the cvs edit command was run and hostname and pathname identify the sandbox from which the command was run.
Example 6-2 shows a fileattr file.
Fconfig.h _watchers=doppel>edit+unedit+commit;_watched= Fhandheld.c _watchers=doppel>edit+unedit+commit;_watched= Fmain.c _watchers=doppel>edit+unedit+commit,jenn> edit+unedit+commit+tedit+tunedit+tcommit;_watched=;_editors=jenn>Fri Sep 27 19:15:18 2002 GMT+helit+/home/jenn/cvs/wizzard/src Fserver.c _watchers=doppel>edit+unedit+commit;_watched= D _watchers=doppel>edit+unedit+commit
CVS uses read and write locks to prevent processes from simultaneously writing to or reading from the same repository files. These locks are signalled by the presence of a file or directory with a specific name pattern in project directories.
CVS locks the repository one directory at a time, each lock locking a directory, its Attic and CVS subdirectories, and all files in that directory. A lock does not lock subdirectories, so to lock an entire directory tree each subdirectory must be locked individually.
These are the file and directory names that indicate CVS locks:
The presence of this directory in any repository directory indicates that a process holds the master lock in the current directory.
The presence of a file with this name or name pattern in a repository directory indicates that a process holds a read lock in the current directory.
The presence of a file with this name or name pattern in a repository directory indicates that a process holds a write lock in the current directory.
Holding a master lock prohibits other programs that honor such locks from creating new locks in the locked directory. Any program that honors the locks will not read from or write to a file unless it has locked the directory the file is in. Master locks are directories, because in most operating systems directory creation is done as a single operation and can't be interrupted by another process.
A read lock is a nonexclusive lock, which permits others to read files while the directory is locked but not to write to them. You create a master lock before you create a read lock, to ensure that no one else locks the directory while you are trying to lock it. You can release the master lock once you have your read lock, to allow others to read the files as well.
To obtain a read lock:
Create the #cvs.lock directory in the directory you wish to lock. In most operating systems, directory creation is an atomic process. Check the response code for the directory-creation command; if it fails because the directory already exists, wait and try again later.
Once you have the master lock, create #cvs.rfl or #cvs.rfl.extension in the #cvs.lock directory. extension is any data you wish to add and is often a process ID. Remove the #cvs.lock directory to release the master lock.
When you are finished reading in the #cvs.lock directory, you must remove the #cvs.rfl file to release the read lock.
A write lock is an exclusive lock, which prohibits others from reading or writing the files while you hold the lock. CVS prohibits reading or writing by having processes that use a write lock also hold the master lock until after they release the write lock. The write-lock file exists primarily to provide the process ID, so that you can identify which process is holding the lock if you need to clear it.
To obtain a write lock:
Obtain the master lock in the same way that you obtain a read lock.
Check for the presence of a read lock by looking for a #cvs.rfl or #cvs.rfl.* file. If there is a read lock, release the master lock, wait, and try again.
Once you have a master lock on a directory with no read lock, create a write lock by creating a #cvs.wfl or #cvs.wfl.extension file in the target directory, where the extension may be a process ID or other identifier. Retain the master lock.
When you are finished writing to the repository, release the write lock first. Then release the master lock.
If you are trying to lock multiple directories simultaneously and you encounter an existing lock, you should release all the locks you have obtained before waiting and trying again. This helps avoid deadlocks.
A deadlock occurs when two processes attempt to lock multiple directories and each is holding one directory locked while attempting to lock a directory the other is holding. Such a deadlock prevents either process from continuing.