Как данные хранятся в репозитории

В большинстве случаев неважно, как именно CVS хранит информацию в репозитории. В действительности, формат уже менялся однажды и, скорее всего, изменится в будущем. Так как в большинстве случаев весь доступ к репозиторию происходит посредством команд CVS, такие изменения не приводят к каким-либо разрушениям.

Однако, в некоторых случаях необходимо знать, как именно CVS хранит данные в репозитории, например, если вы хотите следить за блокировками файлов, которые делает CVS или если вам потребуется изменить права доступа к файлам в репозитории.

Где хранятся файлы в репозитории

Общая структура репозитория — это дерево каталогов, соответствующее каталогам в рабочей копии. Предположим, например, что репозиторий находится в

/usr/local/cvsroot

Вот возможное дерево каталогов (показаны только каталоги):

/usr
|
+--local
| |
| +--cvsroot
| | |
| | +--CVSROOT
    |       (административные файлы)
    |
    +--gnu
    |   |
    |   +--diff
    |   |   (исходный текст GNU diff)
    |   |
    |   +--rcs
    |   |   (исходный текст RCS)
    |   |
    |   +--cvs
    |       (исходный текст CVS)
    |
    +--yoyodyne
        |
        +--tc
        | |
        | +--man
        | |
        | +--testing
        |
        +---(другое программное обеспечение фирмы Yoyodyne)

Внутри каталогов находятся файлы истории для каждого файла, находящегося под контролем версий. Имя файла истории состоит из имени соответствующего файла и суффикса ,v. Вот как выглядит дерево каталогов для yoyodyne/tc:

$CVSROOT
|
+--yoyodyne
| |
| +--tc
| | |
    +--Makefile,v
    +--backend.c,v
    +--driver.c,v
    +--frontend.c,v
    +--parser.c,v
    +--man
    |   |
    |   +--tc.1,v
    |
    +--testing
         |
         +--testpgm.t,v
         +--test2.t,v

Файл истории содержит, помимо всего прочего, достаточно информации, чтобы воссоздать любую ревизию файла, журнал всех зафиксированных изменений и имена всех пользователей, сделавших эти изменения. Файлы истории известны как RCS-файлы, потому что первой программой, которая создавала файлы этого формата, была система контроля версий RCS. Полное описание формата файлов находится на странице руководства rcsfile(5), распространяемого вместе с RCS, или в файле doc/RCSFILES из комплекта исходных текстов CVS. Этот формат файла используется повсеместно — множество других программ могут по меньшей мере импортировать файлы этого формата.

Файлы RCS, используемые в CVS, несколько отличаются от стандартного формата. Волшебные ветки — самое большое отличие; см. раздел “Волшебные номера веток”. Имена меток, которые позволяет использовать CVS, являются подмножеством тех, что позволены в RCS; см. раздел “Метки ревизий”.

Права доступа к файлам

Все файлы ,v создаются с правами “только для чтения”, и вам не следует изменять эти права доступа. Каталоги в репозитории должны быть доступны для записи тем, кому разрешено изменять файлы в каждом каталоге. Это обычно означает, что вам нужно создать группу пользователей UNIX (см. страницу руководства group(5)), состоящую из лиц, участвующих в создании проекта, и настроить репозиторий так, чтобы эта группа была владельцем каталога с проектом.

Это означает, что ограничивать доступ к файлам можно только на уровне каталога.

Заметьте, что пользователи должны иметь права на запись в каталог и для извлечения файлов, потому что CVS должна создать файлы блокировки.

Заметьте также, что пользователи должны иметь права на запись в файл CVSROOT/val-tags. CVS использует этот файл, чтобы отслеживать, какие метки разрешены (этот файл иногда обновляется, когда используются и когда создаются метки).

Каждый RCS-файл принадлежит пользователю, который последним зафиксировал изменения в этот файл. Этот факт не столь важен, главное — кто владелец каталога.

CVS пытается установить адекватные права доступа к файлам для новых каталогов, которые создаются в дереве, но если вам требуется, чтобы новый каталог имел права доступа, отличающиеся от его родительского каталога, вы должны задать это вручную. Если вы установите переменную окружения CVSUMASK, то она будет задавать, какие права доступа к файлам CVS использует при создании каталогов и/или файлов в репозитории. CVSUMASK не влияет на права доступа к файлам в рабочем каталоге; такие файлы имеют права, обычные для новых файлов, разве что только иногда CVS создает их с правами только для чтения.

Заметьте, что при использовании клиент-серверного CVS (см. раздел “Сетевые репозитории”) не существует нормального способа установить CVSUMASK; установка его на клиентской машине не играет роли. Если вы соединяетесь с помощью rsh, то можете устанавливать CVSUMASK в файле .bashrc или .cshrc, как описано в документации на вашу операционную систему. Это поведение может измениться в будущей версии CVS; не полагайтесь на то, что установка CVSUMASK на клиентской машине не играет роли.

При использовании сервера парольной аутентификации (pserver) обычно требуются гораздо более жесткие права доступа к каталогу $CVSROOT и каталогам, находящимся в нём; см. раздел “Настройка сервера для парольной аутентификации”.

Некоторые операционные системы позволяют определенным программам выполнять операции, которые не может выполнять тот, кто вызывает эти программы. Таковы, например, возможности setuid или setgid в UNIX или установленные образы в VMS. CVS не разрабатывался, чтобы использовать такие возможности, и поэтому попытки установить CVS таким образом обеспечат защиту только лишь от случайных ошибок; те, кто желает обойти защиту, смогут это сделать и, в зависимости от конкретных условий, смогут получить доступ еще куда-либо помимо CVS. Вы можете попробовать использовать pserver. Эта возможность также способна создать ложное чувство безопасности или открыть дыру, большую чем та, которую вы пытаетесь закрыть, поэтому внимательно прочтите главу о безопасности сервера парольной аутентификации, если вы собираетесь его использовать. Дополнительная информация в разделе “Настройка сервера для парольной аутентификации”.

Специфические для Windows права доступа

Некоторые вопросы, связанные с правами доступа, специфичны для операционных систем класса Window (Windows 95/98, Windows NT и, скорее всего, будущие подобные операционные системы. Часть нижесказанного может быть применима к OS/2, хотя я не уверен).

Чердак

Вы заметите, что иногда CVS помещает RCS-файлы в каталоге Attic (“чердак”). Например, если CVSROOT — это /usr/local/cvsroot, и мы говорим о файле backend.c в каталоге yoyodyne/tc, то обычно этот файл находится в

/usr/local/cvsroot/yoyodyne/tc/backend.c,v

Если же он попадает на чердак, то он будет находиться в

/usr/local/cvsroot/yoyodyne/tc/Attic/backend.c,v

С точки зрения пользователя неважно, находится файл на чердаке или нет, так как CVS сам следит за этим и при необходимости заглядывает на чердак в поисках файла. В случае же, если вы хотите знать точно, то RCS-файл хранится на чердаке тогда и только тогда, когда головная ревизия ствола находится в состоянии dead (мертвое). “Мертвое” состояние означает, что файл был удален или же никогда не добавлялся в эту ветку. Например, если вы добавите файл в ветку, то его стволовая ревизия будет в “мертвом” состоянии, а ревизия на ветке — нет.

Каталог CVS в репозитории

Каталог CVS в каждом репозитории содержит информацию об атрибутах файлов (в файле CVS/fileattr); смотри fileattr.h среди исходных текстов CVS за дополнительной информацией. В будущем в этом каталоге могут оказать другие дополнительные файлы, поэтому сегодняшние реализации должны игнорировать неизвестные файлы.

Это поведение реализовано только в версиях 1.7 и выше.

Блокировки в репозитории

Эта глава ориентирована на людей, пишущих утилиты, обращающиеся к репозиторию CVS, не конфликтуя при этом с другими программами, обращающимися к тому же репозиторию. Если вы запутаетесь в описываемых здесь концепциях, как то блокировка чтения, блокировка записи и мертвая блокировка, то обратитесь к литературе по операционным системам или базам данных.

Файлы в репозитории, чьи имена начинаются с #cvs.rfl — это блокировки чтения. Файлы, чьи имена начинаются с #cvs.wfl — это блокировки записи. Старые версии CVS (до версии 1.5) создавали также файлы с именами, начинающимися с #cvs.tfl, но такие файлы здесь не обсуждаются. Каталог #cvs.lock служит основной блокировкой, то есть перед тем, как создавать какую-либо еще блокировку, сначала необходимо создать основную блокировку.

Чтобы создать блокировку чтения, сначала создайте каталог #cvs.lock. В большинстве операционных систем операция создания каталога является атомарной. Если попытка создания завершилась неудачно, значит, основная блокировка уже существует, поэтому подождите немного и попробуйте еще. После получения блокировки #cvs.lock создайте файл, чье имя состоит из #cvs.rfl, и информацией по вашему выбору, например, имя машины и номер процесса. Потом удалите каталог #cvs.lock, чтобы снять основную блокировку. Теперь можно читать репозиторий. Когда чтение окончено, удалите файл #cvs.rfl, чтобы снять блокировку чтения.

Чтобы получить блокировку записи, сначала создайте каталог #cvs.lock, как и в случае с блокировкой чтения. Затем убедитесь, что в репозитории нет файлов, чьи имена начинаются с #cvs.rfl. Если они имеются, удалите #cvs.lock, подождите немного и попробуйте снова. Если блокировок чтения нет, создайте файл с именем, состоящим из #cvs.wfl и какой-нибудь информации по вашему выбору, например, имени машины и номера процесса. Не удаляйте блокировку #cvs.lock. Теперь вы можете писать в репозиторий. Когда запись окончена, сначала удалите файл #cvs.wfl, а затем каталог #cvs.lock. Заметьте, что в отличие от файла #cvs.rfl, файл #cvs.wfl имеет чисто информационное значение; он не оказывает блокирующего эффекта, который в данном случае достигается использованием главной блокировки (#cvs.lock).

Заметьте, что каждая блокировка (чтения или записи) блокирует единственный каталог в репозитории, включая Attic и CVS, но не включая подкаталоги, которые представляют собой другие каталоги, находящиеся под контролем версий. Чтобы заблокировать целое дерево, вам следует заблокировать каждый каталог (заметьте, что если вы не сможете получить хотя бы одну блокировку в этом процессе, то следует отменить все уже полученные блокировки, затем подождать и попробовать снова, во избежание мертвых блокировок.)

Заметьте также, что CVS ожидает, что доступ к отдельным файлам foo,v контролируется блокировками записи. RCS использует в качестве блокировок файлы ,foo,, но CVS не поддерживает такую схему, поэтому рекомендуется использование блокировки записи. Смотри комментарии к функции rcs_internal_lockfile в исходном коде CVS, где находится дополнительное обсуждение и мотивация.

Как в каталоге CVSROOT хранятся файлы

Каталог $CVSROOT/CVSROOT содержит различные административные файлы. В каком-то смысле этот каталог подобен любому другому каталогу в репозитории; он содержит RCS-файлы, чьи имена заканчиваются на ,v, и многие команды CVS оперируют с ними обычным образом. Однако, имеется несколько различий.

Для каждого административного файла, в дополнение к RCS-файлу, хранится его последняя ревизия. Например, есть RCS-файл loginfo,v и файл loginfo, содержащий последнюю ревизию, находящуюся в loginfo,v. Когда вы фиксируете административный файл, CVS должен написать:

cvs commit: Rebuilding administrative file database

и обновить его извлеченную копию в $CVSROOT/CVSROOT. Если это не так, значит, что-то случилось с CVS . Чтобы ваши CVS обращался с вашими собственными файлами точно так же, вы можете добавить их имена в административный файл checkoutlist.

По умолчанию, файл modules ведет себя как описано выше. Если же он становится очень большим, то хранение в виде плоского файла может привести к медленному поиску модулей (я не уверен, что это все еще столь же важно, как и тогда, когда эта возможность впервые появилась; я не видел расчетов быстродействия). Таким образом, внеся определенные изменения в исходный код CVS, можно хранить файл модулей в базе данных, которая имеет интерфейс с ndbm, например, Berkeley db или GDBM. Если эта опция используется, то база данных модулей будет храниться в файлах modules.db, modules.pag и/или modules.dir.