Если описатель открытого файла указывает на наличие у вызывающего потока прав на чтение файла, NtReadFile создает IRP типа IRPMJREAD и посылает его драйверу файловой системы, в которой находится файл. NtReadFile получает объект FSD, хранящийся в объекте «файл», и вызывает IoCallDriver. Диспетчер ввода-вывода находит FSD с помощью объекта FSD и передает IRP этому драйверу файловой системы.

Если считываемый файл может быть кэширован (т. е. при открытии файла в функцию CreateFile не передан флаг FILE_FLAG_NO_BUFFERING), FSD проверяет, инициировано ли кэширование для этого объекта «файл». Если да, поле PrivateCacheMap объекта «файл» указывает на структуру закрытой карты кэша (см. главу 11). B ином случае поле PrivateCacheMap будет пустым. Кэширование объекта «файл» инициируется FSD при первой операции записи или чтения над этим объектом, для чего FSD вызывает функцию CcIni-tializeCacheMap диспетчера кэша, и диспетчер кэша создает закрытую и общую карты кэша, а также объект «раздел» (если это еще не сделано).

Убедившись, что кэширование файла разрешено, FSD копирует данные запрошенного файла из виртуальной памяти диспетчера кэша в буфер, указатель на который передан функции ReadFile вызывающим потоком. Файловая система выполняет копирование в рамках блока try/except, что позволяет перехватывать все ошибки, которые могут возникнуть, если приложение указало неверный буфер. Для копирования файловая система использует функцию CcCopyRead диспетчера кэша, которая принимает в качестве параметров объект «файл», смещение внутри файла и длину данных.

Диспетчер кэша, выполняя CcCopyRead, получает указатель на общую карту кэша, хранящуюся в объекте «файл». Вспомните из главы 11, что эта карта хранит указатели на блоки управления виртуальными адресами (VACB) и что один элемент VACB соответствует 256-килобайтному блоку файла.



16 из 207