Антон Ананич
Captive – это первая полнофункциональная Open Source-реализация
NTFS-драйвера. С помощью Captive вы можете монтировать Windows
NT/2k/XP/2k3-разделы и записывать на них данные без опасения потерять их.
FUSE (Filesystem in USErspace) – это драйвер для Linux и FreeBSD, который
позволяет непривилегированным пользователям создавать их собственные драйверы
файловых систем без написания кода, выполняемого в режиме ядра.
FUSE может быть особенно полезной для разработки
драйверов виртуальных файловых систем (virtual file systems, VFS). Это файловые
системы, которые не сериализуют данные непосредственно, а всего лишь выступают
прослойкой (abstraction layer) или оберткой (wrapper) над существующими
файловыми системами или специальными устройствами.
В нашем журнале уже была статья о FUSE [1]. С тех
пор проект развился и сильно возмужал.
FUSE позволяет разрабатывать драйверы файловых
систем не только на языке С. Так как эти драйверы выполняются в
пользовательских процессах, то они могут быть реализованы практически на любом
языке программирования. Официально поддерживаются C, C++, Java, C#, Haskell,
TCL, Python, Perl, Sh (UNIX shell script), Ocaml, Pliant и Ruby.
Существует несколько десятков
файловых систем (на сегодня более 50) на базе FUSE. Рассказать о всех
в рамках этой статьи просто невозможно. Поэтому я перечислю некоторые
задачи, которые могут быть решены с помощью FUSE:
n шифрование и сжатие файлов «на лету»;
n SMB (монтирование при первом обращении,
кэширование);
n FTP, SSh, WebDAV, Gmail и т. д.;
n монтирование содержимого архивов (rar, zip, tar,
bzip2, gzip и т. д.);
n монтирование специфических устройств (iPod, мобильники
Siemens, Apple iPhoto DPAP и т. д.);
n монтирование NTFS в режиме read&write
(полноценная запись в отличие от той, что содержится в ядре по
умолчанию);
n хранение файлов в реляционной БД.
FUSE работает на Linux 2.4, Linux 2.6 и FreeBSD
[2]. Начиная с версии 2.6.14rc1 FUSE входит в ядро Linux. Изначально FUSE была
частью проекта AFVS [3], но теперь является отдельным проектом на SourceForge
[4].
Как работает FUSE?
Разработать драйвер файловой системы с использованием FUSE очень просто. В
качестве доказательства создатели FUSE приводят на своем сайте пример драйвера
файловой системы Hello world, написанный на языке С, исходный код которого
занимает меньше 100 строк. Этот исходный код доступен по адресу: http://fuse.sourceforge.net/helloworld.html.
На рис. 1 показано, как происходит
системный вызов (например, stat) в драйвере Hello world.

Рисунок 1. Файловая система Hello
world
Драйвер и библиотека FUSE общаются между собой с
помощью файлового дескриптора, получаемого при открытии /dev/fuse. Этот файл
может быть открыт несколько раз. При этом для каждой монтируемой ФС
генерируется свой дескриптор.
Сегодня вы узнаете, как можно монтировать разделы
NTFS в режиме read+write.
Как работает Captive?
Существует два FUSE-драйвера для NTFS: ntfsmount и сaptive. Первый
из них использует тот же код, что и kernel-драйвер. По сути это один
и тот же драйвер, который выполняется по-разному. Этот драйвер
написан с нуля. В ходе его разработки проводилась большая работа по реверс-инжинирингу.
Этот драйвер пока ещё не очень стабилен и предназначен в основном для
чтения данных. Записывать он тоже может, но единственное, что можно сделать
с помощью этого драйвера – это изменить содержимое существующего файла,
оставляя прежним его размер. Это может быть полезно, если вы хотите
использовать некий файл-контейнер, лежащий на NTFS, например, PGP-диск или
виртуальный винчестер для VMWare. Но в этом случае лучше использовать вариант
драйвера, выполняемый в режиме ядра, так как он работает гораздо быстрее.
Captive NTFS использует другой подход. Наподобие
того, как это делается в Wine, captive подгружает в адресное пространство
позаимствованный из Windows драйвер ntfs.sys и использует его код для записи в
NTFS. Это дает достаточно высокую гарантию сохранности данных. Ну так давайте
же скорее установим его!
Установка и использование
Для начала вам понадобится FUSE. Если вы приверженец FreeBSD, то вам
повезло: fuse4freebsd уже есть в портах. Достаточно установить пакеты sysutils/fusefs-kmod
и sysutils/fusefs-libs.
Я пользуюсь Gentoo Linux и поэтому все, что будет
сказано дальше в основном относится к этому дистрибутиву и ядру Linux.
Итак, в Gentoo установка проходит так:
emerge -av sys-fs/fuse
modules-update
modprobe fuse
chmod 666 /dev/fusе
Для удобства можно добавить FUSE в автозагрузку:
echo "fuse"
>> /etc/modules.autoload.d/kernel-2.6
Неудобство этого подхода в том, что каждый раз,
когда вы пересобираете ядро, вам необходимо будет пересобирать и sys-fs/fuse.
Если вы используете ядро 2.6.14 или старше, то вы можете просто включить
поддержку FUSE прямо в ядре.
Symbol: FUSE_FS [=m]
Prompt: Filesystem in Userspace
support
Defined at fs/Kconfig:465
Location:
-> File systems
Следующий шаг – установка captive. Вы можете
скомпилировать captive из исходников или использовать готовый rpm, скачав его
со страницы проекта: http://www.jankratochvil.net/project/captive/#download.
В портах Gentoo captive уже присутствует, так что установка не составляет
труда.
echo "sys-fs/captive
~x86" >> /etc/portage/package.keywords
echo "sys-fs/captive -gtk"
>> /etc/portage/package.use
emerge -av captive
Если вы используете Debian-based-дистрибутив, то
вам придется конвертировать rpm в deb:
alien
captive-static-1.1.7-0.i386.rpm
dpkg -i
captive-static_1.1.7_1.i386.deb
Если вы хотите скомпилировать captive из исходников,
то это лучше всего сделать так:
./configure –enable-install-pkg=no
make
make install
Теперь остается переписать файлы
${WINDIR}/system32/ntoskrnl.exe и ${WINDIR}/system32/drivers/ntfs.sys в /var/lib/captive/.
Я это сделал с помощью Samba. Если у вас нет доступа к установленной Windows
NT/2000/XP/2003Server, то вам, пожалуй, придется качать Service Pack с
сайта Microsoft и извлекать эти файлы оттуда с помощью cabextract. WinXP SP2 доступен
по адресу [5].
Вот и всё! Теперь надо не забыть отмонтировать
NTFS-раздел:
umount /dev/hda1
mount -t captive-ntfs /dev/hda1
/mnt/tmp/ -o -–rw
Обратите внимание, что параметры, которые мы
хотим передать captive, должны начинаться с двух тире, а те параметры,
которые предназначены для FUSE, передаются обычным образом.
Для удобства можно добавить в /etc/fstab запись,
соответствующую NTFS-разделу:
/dev/hda1 /mnt/captive captive-ntfs
noauto,--rw 0 0
Архитектура
Captive состоит из двух частей – это собственно сам драйвер и утилита
настройки captive-install-acquire (см. рис. 2). Эта утилита разработана под Gnome
очень сильно и тянет за собой много зависимостей. А вот функционал у неё
довольно скромный: она ищет на NTFS-разделах файлы ntfs.sys, fastfat.sys,
ntoskrnl.exe и sdfs.sys и переписывает их в директорию /var/lib/captive. У
меня она где-то нашла эти файлы с испанской (!) локалью. Если такие файлы найти
не удается, то captive-install-acquire может скачать с сайта www.microsoft.com service pack и взять их
оттуда. И последнее. Эта утилита добавляет в /ets/fstab записи об
NTFS-разделах, но без опции --rw, и поэтому всё равно приходится править
руками.

Рисунок 2. Установка captive
с помощью captive-install-acquire
К нашей удаче существует возможность установить
только драйвер. В Gentoo это делается с помощью USE-флага -gtk, а если вы
собираете пакет из исходников, то нужно задать опцию -enable-install-pkg=no
для скрипта configure. Но даже в этом случае вам придется установить gnomevfs, libonobo
и orbit. Давайте разберемся, для чего это нужно (см. рис. 3).

Рисунок 3. Принцип работы captive

Рисунок 4. Captive API
При монтировании файловой системы FUSE подгружает
sandbox master – компонент captive, который постоянно находится в памяти. Sandbox
master контролирует работу sandbox slave. Этот slave выполняется в отдельном
процессе. В адресное пространство этого процесса подгружаются ntosknl.exe и ntfs.sys
прямо, как в Wine. Этот процесс и называется sandbox – песочница. Внутри
песочницы captive делает вызовы бинарного кода, предназначенного для выполнения
в адресном пространстве несколько иной структуры. Кроме того, этот код
предназначен для выполнения в более богатом разными компонентами
окружении. Конечно, этот код должен выполняться на нулевом кольце, а не
на третьем. В силу сказанного ассемблерный код из ntoskrnl.exe и *.sys
довольно часто приводит к аварийному завершению процесса. Segmentation, как
говорится, fault. В ходе поставленных мною экспериментов такое падение мне
удавалось наблюдать до десяти раз за время распаковки архива с исходниками
captive (2,9 Мб). Когда песочница ломается, sandbox master перезапускает
песочницу повторно и продолжает выполнение сначала неудачной транзакции,
поэтому для конечного пользователя этот крах остается незамеченным и не
приводит к потере данных.
Также мне хотелось бы отметить, что все
компоненты captive реализованы на языке C. Это положительно влияет на
производительность. IPC при управлении песочницей реализован на основе CORBA
(вот для чего нужны libonobo и orbit). А для чего же gnome-vfs? Если
взглянуть в ChangeLog, то становится ясно, что изначально captive
разрабатывался исключительно для gnome-vfs. Проект стартовал в октябре 2002
года. В августе 2003 была добавлена поддержка LUFS, a в декабре 2005 LUFS была заменена
на FUSE. Проекты gnome-vfs, fuse и lufs стартовали соответственно в
августе 1999, ноябре 2001 и августе 2002 годов.
Скорее всего разработчики думали, что captive не
только никогда не войдет в официальное ядро, но и вообще за пределами Gnome
использоваться не будет. Как мы увидим далее, возможность использования gnome-vfs
вместо FUSE следует рассматривать всерьёз, если вы уделяете внимание
быстродействию файловой системы, так как при использовании gnome-vfs приходится
вместо трех переключений в/из режим(а) ядра делать всего одно.
Производительность
Думаю, вам будет интересно оценить производительность captive. Для этого я
проделал всего два теста. Я засекал с помощью команды time время копирования
одного большого файла и время распаковки архива с большим количеством маленьких
файлов.
# time cp
/usr/portage/distfiles/captive-1.1.7.tar.gz /mnt/tmp/
# time tar -xzf
captive-1.1.7.tar.gz -C /mnt/tmp
Оба этих теста я проделал на разделах NTFS со
сжатием и без него и на reiserfs. Результат вы можете увидеть в таблице 1.
Таблица 1. Результаты замера
производительности
|
|
NTFS
|
compressed NTFS
|
ReiserFS
|
|
Копирование
|
0 m 12.159 s
|
0 m 39.673 s
|
0 m 0.048 s
|
|
Распаковка
|
3 m 10.333 s
|
4 m 22.235 s
|
0 m 1.479 s
|
Признаться, результат оказался несколько
неожиданным. Из таблицы видно, что производительность Captive оставляет желать лучшего.
ReiserFS работает более чем в 150 раз быстрее. Таким образом, если у вас нет
необходимости записывать на NTFS-раздел, то крайне целесообразным будет
использовать read-only-драйвер, поставляемый с ядром. Если вы хотите
использовать VMWare hard drive, BestCrypt диск и т. п., то в этом случае опять
же лучше будет использовать драйвер из ядра.
Если вам жизненно необходимо создавать и удалять
файлы, менять их размер, то у вас есть два варианта: Captive и VMWare. Captive
вполне подойдет, если вам нужно отредактировать документ на NTFS-разделе или
сбросить туда пару файлов. Если этот раздел расположен на USB 1.0, то вы можете
даже не заметить разницы в скорости. В случае когда вам необходимо писать
на NTFS часто и много, стоит рассмотреть возможность применения VMWare.
Если виртуальная машина использует физический диск, то запись происходит
с такой же скоростью, как и в Windows. Однако в отличие от Captive это
коммерческий продукт. Кроме того, на виртуальную машину нужно будет поставить Windows
NT/2k/XP/2k3, которые тоже не бесплатны. Кроме того, для установки вам придется
пожертвовать 256 Мб памяти и 2 Гб дискового пространства. К тому же VMWare для
работы требуется X Server.
Поэтому невозможно дать универсальные
рекомендации. В каждом конкретном случае вам приходется подбирать
индивидуальное решение.
Ссылки:
1. Яремчук
С. Файловые системы пространства пользователей. – Журнал «Системный
администратор», №6, 2006 г. – 40-43 с. – http://www.samag.ru/cgi-bin/go.pl?q=articles;n=06.2005;a=06.
2. http://fuse4bsd.creo.hu.
3. http://www.inf.bme.hu/~mszeredi/avfs.
4. http://fuse.sourceforge.net.
5. http://www.microsoft.com/downloads/details.aspx?FamilyID=049c9dbe-3b8e-4f30-8245-9e368d3cdb5a.