Последняя сопоставленная страница - PullRequest
1 голос
/ 14 июля 2011

POSIX говорит "Система всегда заполняет нулями любую частичную страницу в конце объекта. Кроме того, система никогда не записывает какие-либо измененные части последней страницы объекта, которые находятся за его концом." , а в документации для Linux и FreeBSD аналогичные формулировки содержатся на их страницах руководства.
Это говорит о том, что, хотя не совсем законно читать последние завершающие байты (так как они находятся за пределами отображенного диапазона), он все еще четко определен и спроектирован таким образом, что может произойти без сбоев. Даже письмо в эту область довольно четко определено.

С другой стороны, в документации Windows ничего не говорится о концевых байтах в диапазоне меньше размера блока, и действительно предупреждает, что создание отображения, большего, чем файл, увеличит размер файла, и не обязательно ноль данных.
Я склонен полагать, что это либо неверная информация, либо историческая (может быть, восходит к Win95?). SetFileValidData требует нестандартных прав пользователя из-за соображений безопасности, которые могут сделать данные из ранее удаленного файла видимыми. Если бы разработчики ядра Windows позволяли кому-либо тривиально обойти это путем сопоставления любого случайного файла, они должны были бы быть довольно глупыми.
Мое наблюдение в Windows XP заключается в том, что любые новые страницы, по-видимому, извлекаются из нулевого пула, и для обратной записи пустой страницы либо файл создается бесшумно разреженным, либо обратная запись выполняется очень, очень интеллектуальным способом (без заметной задержки время, даже в диапазоне гигабайт).

Так в чем же вопрос?

Мне нужно вычислить значения хеш-функции (возможно, тысяч) файлов, чтобы обнаружить подмножество файлов, которые были изменены. В качестве алгоритма можно принять SHA-256, хотя фактический алгоритм на самом деле не имеет значения.
Что само по себе, конечно, не является большой проблемой, но, как и любое программное обеспечение, оно должно работать в кратчайшие сроки и не использовать память, и так далее. Обычные реалистичные ожидания, вы получите: -)

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

Теперь возникает искушение напрямую хэшировать файл с отображением в памяти и полагаться на тот факт, что отображение файла обязательно зависит от страниц памяти. Таким образом, как начальный адрес, так и физически отображаемая длина более или менее гарантированно будут кратны 4 кБ (64 кБ в некоторых системах). Что, конечно, означает, что они автоматически также кратны 64, 128 или любому другому размеру блока, который может иметь хеш.
А по соображениям безопасности фактически ни одна ОС не может позволить себе предоставить страницу, содержащую устаревшие данные.

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

Я, конечно, знаю, что это технически незаконно. Чтение последних байтов за пределами отображенного диапазона несколько сравнимо с высказыванием о том, что malloc(5) всегда в любом случае возвращает 8-байтовый блок, поэтому безопаснее использовать дополнительные 3 байта.

Хотя, кроме этой очевидной вещи, мое предположение о том, что это "просто сработает" разумно, или есть какая-то серьезная проблема, которую я не вижу ни на одной крупной платформе?

Меня не слишком интересуют теоретические или исторические операционные системы, но я бы хотел оставаться несколько портативным. То есть я хотел бы убедиться, что он надежно работает на всем, что вы, вероятно, встретите на настольном компьютере или на «типичном хостинг-сервере» (так, в основном, на Windows, Linux, BSD, OSX).
Если с 1985 года существует операционная система, которая помечает последнюю страницу как нечитаемую и применяет строгие диапазоны байтов в обработчике ошибок, я согласен с этим. Вы не можете (и не должны) делать всех счастливыми.

1 Ответ

1 голос
/ 30 августа 2012

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

Не совсем.Таким образом, вы не могли узнать длину последнего блока (был ли там ноль или он получен из заполнения).Заполнение работает немного по-другому: в одной схеме вы всегда добавляете один 1, а затем 0 с до конца блока.

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

Возможно, он прочитает несколько байтов после конца отображенного диапазона, но он обязательно будет находиться на той же странице.

Я думаю, что это должно работать на Intel / AMD, так как никто ничего не может с этим поделать.Процессоры i386 + имеют сегменты и страницы.Сегменты могут заканчиваться на любой границе байта, но AFAIK ни одна текущая ОС не использует их.Так что, пока вы остаетесь на своей странице, это все ваше.

Так что я думаю, что это может работать так:

  • в случае, если самый последний блок не имеет полный размер, выполните отступы на месте
  • в противном случае, запустите последний раунд на подготовленном константном блоке, как 1000000000000000
...