10. Как мой компьютер хранит информацию на диске?

Когда, работая под Unix, вы смотрите на жёсткий диск, вы видите дерево именованных каталогов (директорий) и файлов. Обычно вам не приходится заглядывать глубже этого, однако будет полезным знать, что происходит уровнем ниже, в случае, если жёсткий диск начнёт барахлить и потребуется спасать файлы. К сожалению, способ объяснять организацию диска от файлов к нижним уровням плох, поэтому я буду объяснять поднимаясь вверх, начав с уровня аппаратного обеспечения.

10.1. Низкоуровневая структура диска и файловой системы

Поверхность вашего диска, на которой хранятся данные, разделена примерно как мишень для метания дротиков — круговые дорожки, разрезанные секторами. Вследствие того, что дорожки, близкие к внешнему краю, имеют бóльшую длину, чем те, что ближе к шпинделю в центре диска, внешние дорожки имеют больше секторов, чем внутренние. Все сектора (или блоки диска (disk block)) имеют одинаковый размер, в современных Unix это обычно 1 двоичная тысяча (1024 8-битовых слов). Каждый блок диска имеет уникальный адрес или номер блока диска (disk block number).

Unix разбивает диск на разделы (disk partitions). Каждый раздел — это непрерывный интервал блоков, используемый отдельно от любого другого раздела, например, файловая система и область подкачки (swap space). Изначально причины, по которым возникла необходимость создавать на диске разделы, это восстановление после сбоев медленных и склонных к возникновению ошибок дисков; границы между разделами уменьшают вероятность возникновения ситуации, когда в результате произвольной ошибки на диске вы целиком теряете к нему доступ. В наши дни более важным является то, что раздел можно объявить доступными только для чтения (read-only) (во избежание модификации злоумышленником критично важных системных файлов) или сделать доступным по сети (с разными целями, которые мы здесь не обсуждаем). Раздел с наименьшим номером (загрузочный раздел (boot partition)) создаётся специально для размещения на нем загружаемого ядра.

Раздел может быть либо областью подкачки (swap space) (используемой для работы виртуальной памяти (virtual memory)) или файловой системой (file system), используемой для хранения файлов. Раздел области подкачки трактуется системой просто как линейная последовательность блоков. Файловые системы, напротив, нуждаются в схеме расположения последовательности блоков файлов. Файлы время от времени изменяются, растут и уменьшаются, поэтому блоки данных файла могут располагаться не последовательно, а быть разбросаны по всему разделу (куда бы ни положила их операционная система, когда нуждалась в свободном блоке). Этот эффект разрозненности называется фрагментацией (fragmentation).

10.2. Имена файлов и каталогов

В каждой файловой системе есть структура, которая адресует расположение файла по его имени, сопоставляя ему блоки диска и адреса их размещения, она называется индексный дескриптор (i-node). Динамическая область, в которой они содержатся, находится рядом с «дном» («bottom») (младшими по номеру блоками) файловой системы (самые младшие блоки используются в служебных целях для создания метки, это мы не будем здесь обсуждать). Каждый индексный дескриптор определяет один файл. Блоки данных файла (каталога) живут выше таблицы индексных дескрипторов (в старших по номеру блоках)

Каждый индексный дескриптор содержит список номеров блоков диска того файла, который он описывает. (В действительности это соответствует истине только на половину, это верно только для небольших файлов, но остальные подробности здесь не важны). Стоит отметить, что индексный дескриптор не содержит имени файла.

Имена файлов живут в структурах, называемых каталоги (directory structures). Каталог — это структура, представляющая собой простую таблицу имён файлов и соответствующих им номеров индексных дескрипторов. Вот почему в Unix файл может иметь несколько настоящих имён (или жёстких ссылок (hard links)); просто в каталог (или в разные каталоги) вносятся записи, указывающие на один и тот же индексный дескриптор.

10.3. Точки монтирования

В простейшем случае вся ваша файловая система Unix полностью живёт на одном разделе. Вы могли видеть такое на небольших персональных системах, но это редкий случай. Более типично, когда она распределена на нескольких разделах диска, возможно, и на разных физических дисках. Например, ваша система может иметь один небольшой раздел, где обитает ядро, немного больший раздел, где живут утилиты ОС, и большой раздел с каталогами пользователей.

Непосредственно в начале загрузки системы вы можете получить доступ только к вашему корневому разделу (root partition), который является (почти всегда) загрузочным. Он содержит корневой каталог файловой системы и является исходной точкой дерева каталогов.

Другие разделы системы подключаются к корневому таким образом, что к этой составленной из разделов файловой системе доступ осуществляется как к цельной. Где-то на полпути, во время процесса загрузки, ваша Unix делает эти некорневые разделы доступными. Она монтирует (mount) каждую из них к соответствующему каталогу в корневом разделе.

Например, если в вашей Unix есть каталог с именем /usr, то, возможно, это точка монтирования раздела, содержащего много программ, установленных в системе, но не требуемых для начальной загрузки.

10.4. Как система узнает где лежит файл

Теперь мы можем взглянуть на файловую систему сверху вниз. Когда вы открываете файл (скажем, такой как /home/esr/WWW/ldp/fundamentals.xml) вот что происходит:

Ваше ядро начинает обзор с корневого каталога файловой системы (корневого раздела). Она ищет каталог с именем «home». Обычно «home» — это точка монтирования большого пользовательского раздела, тогда оно идёт на этот раздел. На верхнем уровне структуры каталога этого пользовательского раздела оно ищет запись с именем «esr» и извлекает номер индексного дескриптора и переходит к нему. Отметим, что в блоках данных, ассоциированных с этим индексным дескриптором, содержится структура каталога, в которой ядро ищет «WWW». Извлекает его индексный дескриптор, и идёт дальше к соответствующему подкаталогу и ищет в нем «ldp». Это даёт ещё один индексный дескриптор каталога. Открывая его, ядро находит номер индексного дескриптора для «fundamentals.xml». Это индексный дескриптор содержит уже не каталог, а список блоков диска, ассоциированных с нужным файлом.

10.5. Владельцы файлов, права доступа и безопасность

Чтобы оградить программы от случайного или умышленного чтения или изменения данных, их не касающихся, в Unix есть система прав доступа (permissions). Первоначально она была разработана для поддержки разделения времени, защищая многочисленных пользователей одной и тоже машины друг от друга, в те дни Unix работала в основном на дорогих разделяемых миникомпьютерах.

Чтобы разобраться в системе прав доступа, вам надо вернуться к описанию понятий пользователей и групп в разделе Что происходит, когда вы входите в систему (log in)?. Каждым файлом владеет пользователь и группа. Изначально владельцем является создатель файла; затем он может быть изменён с помощью программ chown(1) и chgrp(1).

Основные права, которые могут быть ассоциированы с файлом: «чтение» («read») (право чтения данных из файла), «запись» («write») (право изменять его) и «выполнение» («execute») (право запускать его как программу). Каждый файл имеет три набора прав; один для его пользователя-владельца, другой для любого пользователя, входящего в группу владельцев, и один для всех остальных пользователей. «Привилегии», которые вы получаете когда входите в систему, это просто способность читать, изменять и выполнять файлы, имеющие установленные биты прав, соответствующие вашему идентификатору пользователя (user ID) или одной из групп, в которую вы включены; а также файлы, доступные в системе всем.

Чтобы увидеть, как это работает, и как Unix отображает права доступа, давайте посмотрим на списки файлов в гипотетической Unix-системе. вот один из них:


snark:~$ ls -l notes
-rw-r--r--   1 esr      users         2993 Jun 17 11:00 notes

Это обычный файл c данными. Вывод списка говорит нам, что файл принадлежит пользователю «esr» и группе пользователей «users». Возможно, машина, на которой мы работаем, включает всех обычных пользователей в эту группу по умолчанию; другие группы, которые обычно можно встретить на машинах с разделением времени, это «staff», «admin», или «wheel» (по понятным причинам группы не так важны на однопользовательских рабочих станциях и ПК). В вашей Unix по умолчанию может использоваться другая группа, возможно её имя совпадает с именем вашего пользовательского идентификатора.

В строке «-rw-r--r--» представлены биты прав для этого файла. Самая первая позиция предназначена для обозначения каталогов и символьных ссылок, сейчас там прочерк, если бы этот файл был каталогом, то там было бы указано «d», и «l» для символьной ссылки. Следующие три позиции отображают права доступа пользователя, затем три позиции — права доступа группы, и последние три показывают, какие права доступа имеют все остальные пользователи (часто называемые «миром» («world»). Владелец этого файла, пользователь «esr» может и читать и изменять его, другие люди, входящие в группу «users», могут только читать, все остальные также имеют право только читать файл. Это довольно типичный набор прав доступа для обыкновенного файла данных.

Сейчас давайте посмотрим на файл с другими правами доступа. Этот файл GCC, компилятор GNU с языка C.


snark:~$ ls -l /usr/bin/gcc
-rwxr-xr-x   3 root     bin         64796 Mar 21 16:41 /usr/bin/gcc

Этот файл принадлежит пользователю с именем «root» и группе названной «bin»; он может быть перезаписан (изменён) только пользователем root, но прочитан и запущен на выполнение кем угодно. Это обычные настройки владельцев файла и набор прав доступа для предустановленных системных программ. Группа «bin» существует на некоторых Unix для того, чтобы собрать вместе системные команды (её название — это исторический пережиток, сокращение от «binary»). В вашей системе вместо неё может использоваться группа «root» (совсем не тоже самое, что пользователь «root»!).

Имя пользователя «root» — это условное обозначение пользователя с номером идентификатора 0 (ID 0), специальная привилегированная учётная запись пользователя, который может делать в системе все, не взирая ни на что. Доступ к системе под root важен, но небезопасен; при работе в системе под root даже опечатка в команде может полностью повредить или уничтожить критично важные системные файлы, в то время как эта же команда, выполненная под учётной записью обычного пользователя, не сможет этого сделать.

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

О паролях: не записывайте их и не используйте пароли, которые могут быть легко подобраны, такие как имя вашей девушки/парня/супруга. Это удивительно, но именно подобная плохая практика без конца помогает взломщикам. Подходя более универсально, не выбирайте вообще какое-либо слово из словаря; существуют программы называемые взломщик со справочником (dictionary crackers), подбирающие пароли из списка часто используемых слов. Хороший приём выбора пароля, это взять комбинацию слова, цифры и другого слова, например, «shark6cider» или «jump3joy»; это сделает пространство поиска слишком большим для взломщика со словарём. Не используйте эти примеры — после прочтения этого документа взломщики могут добавить их в свои словари.

Теперь рассмотрим третий случай:


snark:~$ ls -ld ~
drwxr-xr-x  89 esr      users          9216 Jun 27 11:29 /home2/esr
snark:~$ 

Этот файл является каталогом (на это указывает «d» в первой позиции). Мы видим, что изменён он может быть только пользователем esr, но читать и выполнять его могут все.

Право чтения даёт возможность просматривать каталог — видеть имена файлов и каталогов, которые он содержит. Право изменять каталог даёт возможность создавать и удалять в нем файлы. Если вы вспомните, что каталог — это файл со списком содержащихся в нем файлов и подкаталогов, то это правило станет понятным.

Право выполнять для каталога означает, что вы можете открывать файлы и подкаталоги, находящиеся в нем. В результате вы получаете доступ к списку индексных дескрипторов каталога. Каталог с полностью запрещённым для всех правом выполнения будет бесполезным.

Время от времени вам бyдут встречаться каталоги, у которых установлено право на выполнение для всех, а доступ на чтение запрещён; это значит, что любой пользователь может получать из него файлы и подкаталоги, только если точно знает их имена (т.к. список файлов не может быть выведен).

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

В заключение, давайте посмотрим на права доступа программы login.


snark:~$ ls -l /bin/login
-rwsr-xr-x   1 root     bin         20164 Apr 17 12:57 /bin/login

Как мы и ожидали, наблюдаем набор прав доступа как у системной команды, за исключением «s», где должен был находиться бит права выполнения для владельца. Это видимое проявление специального права под названием установка прав пользователя «set-user-id» или setuid it.

Бит setuid обычно добавляется к программам, нуждающимся в том, чтобы дать права root обычному пользователю, но контролируемым способом. Когда он устанавливается на исполняемую программу, вы получаете привилегии владельца этой программы на время её выполнения от вашего имени, в любом случае, равносильны они вашим или нет.

Как и сама учётная запись root, программы с установленным битом setuid полезны, но опасны для применения. Любой, кто способен ниспровергнуть или модифицировать setuid-программу, владелец которой root, может использовать её для запуска командного интерпретатора shell с привилегиями пользователя root. По этой причине при открытии файла для записи на большинстве Unix-систем автоматически отключается setuid-бит. Многие атаки на безопасность Unix пытаются использовать ошибки и уязвимости в setuid-программах для их разрушения. Поэтому здравомыслящие системные администраторы особенно настороженно относятся к этим программам и неохотно их устанавливают.

Выше, во время обсуждения прав доступа, мы упустили пару важных деталей, а именно, какая группа владеет и какие права присваиваются файлу и каталогу, когда он создаётся. Вопрос группы спорный, пользователи могут быть членами нескольких групп, но одна из них (обусловленная в записи пользователя в /etc/passwd) является группой, установленной по умолчанию (default group) для этого пользователя и обычно она и указывается в для вновь созданного файла.

История с начальными битами прав доступа немного более сложная. Программа, создающая файл, обычно устанавливает права доступа того, кто её запустил. Однако это можно изменить, поменяв значение переменной пользовательского окружения umask. Umask определяет, какие биты прав доступа при создании файла отключить; наиболее распространённое и устанавливаемое по умолчанию на большинстве систем значение -------w- или 002, которое выключает бит права изменения миром. За дополнительными подробностями о переменной umask можно обратиться к руководству (man) по вашему shell.

Начальное значение группы для каталога также немного сложнее. На некоторых Unix для нового каталога устанавливается группа создающего его пользователя (это соглашение в стиле System V); на других он наследует группу родительского каталога (соглашение в стиле BSD). В некоторых современных Unix, включая Linux, последнее поведение может быть выбрано установкой для каталога атрибута set-group-ID (chmod g+s).

10.6. О неисправностях файловых систем

Ранее я упоминал, что файловые системы могут быть хрупкими. Мы уже знаем, что для того, чтобы система могла добраться до файла, ей надо попрыгать в «классики» и цепочка из каталогов и ссылок на индексные дескрипторы может быть произвольно длинной. Теперь допустим, что на вашем жёстком диске образовался плохой участок.

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

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

Если все это звучит так, как-будто Unix ужасно сложная и склонная к сбоям система, то могу успокоить вас тем, что эти проверки, осуществляемые во время загрузки, обычно выявляют и исправляют средние проблемы до того как они станут действительно бедственными. Другие операционные системы не оснащены подобными средствам, что ускоряет загрузку, но оставляет вам большие сложности при попытках восстановления вручную (и если у вас есть Norton Utilities или подобные программы, это только добавит вам самонадеянности...).

Одно из направлений в текущих разработках Unix это журналируемые файловые системы (journalling file systems). Они организуют движение информации таким образом, что гарантируется устойчивое и непротиворечивое состояние данных на диске и оно может быть восстановлено после сбоя. Это значительно увеличивает скорость проверки целостности при загрузке.