Антон Ананич
Переключи драйвер NTFS в режим read-write
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:
- шифрование и сжатие файлов «на лету»;
- SMB (монтирование при первом обращении, кэширование);
- FTP, SSh, WebDAV, Gmail и т. д.;
- монтирование содержимого архивов (rar, zip, tar, bzip2, gzip и т. д.);
- монтирование специфических устройств (iPod, мобильники Siemens, Apple iPhoto DPAP и т. д.);
- монтирование NTFS в режиме read&write (полноценная запись в отличие от той, что содержится в ядре по умолчанию);
- хранение файлов в реляционной БД.
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.
Поэтому невозможно дать универсальные рекомендации. В каждом конкретном случае вам приходется подбирать индивидуальное решение.
Ссылки:
- Яремчук С. Файловые системы пространства пользователей. – Журнал «Системный администратор», №6, 2006 г. – 40-43 с. – http://www.samag.ru/cgi-bin/go.pl?q=articles;n=06.2005;a=06.
- http://fuse4bsd.creo.hu.
- http://www.inf.bme.hu/~mszeredi/avfs.
- http://fuse.sourceforge.net.
- http://www.microsoft.com/downloads/details.aspx?FamilyID=049c9dbe-3b8e-4f30-8245-9e368d3cdb5a.