среда, 8 апреля 2009 г.

Но почему биты называются FILE_SHARE_READ и FILE_SHARE_WRITE?

Это перевод Why is it FILE_SHARE_READ and FILE_SHARE_WRITE anyway? Автор: Ларри Остерман.

Пост Реймонда о битах FILE_SHARE_* напомнил мне историю о том, откуда вообще взялись биты типа FILE_SHARE_READ.

В MS-DOS была такая же семантика разделения файлов (file sharing semantics) как и в NT (ok, NT добавляет ещё флаг FILE_SHARE_DELETE - подробнее об этом позже). Но на MS-DOS семантика разделения файлов опциональна - вы должны были запустить утилиту share.com, чтобы использовать её. Это объясняется тем, что на однозадачной операционной системе всегда работает только одно приложение, поэтому семантика разделения файлов не нужна. Если только вы не использовали файловый сервер - в этом случае Microsoft настоятельно рекомендовала запускать утилиту.

В MS-DOS режим разделения контролировался тремя битами "режим разделения" (“sharing mode”). Документированными значениями для "режима разделения" были:
000 – Режим совместимости. Любой процесс может открыть файл с этим режимом любое кол-во раз. Открытие файла будет неудачно, если файл уже был открыт в любом другом режиме.
001 – Запретить всё. Открытие будет неудачно, если файл был открыт в режиме совместимости, для чтения или для записи. Даже если файл был открыт текущим-же процессом.
010 – Запретить запись. Открытие будет неудачным, если файл был открыт в режиме совместимости или для записи любым процессом.
011 – Запретить чтение. Открытие будет неудачным, если файл был открыт в режиме совместимости или для чтения любым процессом.
100 – Ничего не запрещать. Открытие будет неудачным, если файл был открыт в режиме совместимости любым процессом.
Вместе с битами "режима разделения" пристыковывались биты "кода доступа" (“access code”). Для них было всего три законных значения: Чтение, Запись и оба сразу (Чтение/Запись).

Дизайнеры набора Win32 API (в частности, дизайнер подсистемы ввода-вывода) как только взглянули на эти флаги - так сразу же вскинули руки в отвращении. По его мнению, с этими определениями есть две большие проблемы:
  1. Из-за того, что биты разделения определяются как отрицание чего-либо, то становится очень сложно определить, что же в итоге будет разрешено и запрещено. Если вы открываете файл для записи в режиме запрета чтения: что при этом произойдёт? Как насчёт режима запрета записи – он допускает чтение или нет?
  2. Из-за того, что режимом по-умолчанию является режим “совместимости”, это означает, что по-умолчанию большинство приложений не могут гарантировать согласованность своих данных. Вместо того, чтобы быть защищённым по-умолчанию, вам нужно делать ещё какие-то доп. действия, чтобы гарантировать, что никто больше не трогает ваши данные.
Поэтому дизайнер подсистемы ввода-вывода предложил инвертировать семантику битов разделения доступа. Вместо того, чтобы биты запрещали доступ, они теперь РАЗРЕШАЮТ доступ. Вместо того, чтобы по-умолчанию разрешать доступ, теперь по-умолчанию доступ будет запрещён. Приложению нужно явно указывать, что оно хочет дать доступ к файлу и другим, пока оно работает с ним.

Это изменение красиво решает кучу проблем, существовавших при одновременном запуске нескольких приложений MS-DOS – если одно приложение работало; другое приложение могло втихую испортить данные, с которыми работало первое.

Итак, мы можем объяснить, что флаги FILE_SHARE_READ и FILE_SHARE_WRITE являются более понятной и безопасной версией разрешений доступа DOS. Но что насчёт FILE_SHARE_DELETE? Откуда, чёрт возьми, он взялся? Ну, он был добавлен для Posix-совместимости. В подсистеме Posix, так же, как и в *nix, файл может быть удалён (unlinked), пока он всё ещё открыт. Кроме того, когда вы переименовываете файл в NT, операция переименования открывает исходный файл для доступа удаления (в конце концов, операция переименования - это создание нового файла в каталоге-назначении и удалении файла из старого места).

Но приложения DOS не ожидают, что файлы могут быть удалены (или переименованы), пока они с ними работают - так что нам надо иметь какой-нибудь механизм, чтобы запретить системе удалять (или переименовывать) файл, если приложению это важно. Вот тут на сцену и выходит дополнительный бит FILE_SHARE_DELETE – это флаг, который говорит системе: “ничего страшного, если кто-то захочет удалить или переименовать этот файл, пока я с ним работаю”.

Загрузчик NT пользуется этим флагом – когда он открывает DLL или приложение для выполнения, он указывает FILE_SHARE_DELETE. Это означает, что вы можете переименовать исполняемый файл запущенного приложения (или загруженной DLL). Это может оказаться полезным, если вы хотите обновить DLL, которая сейчас используется приложением (почему нельзя использовать для этого удаление файла). Я всегда так делаю, когда работаю с winmm.dll. Т.к. winmm.dll используется кучей процессов в системе (включая те, которые нельзя остановить), я не могу просто закрыть все процессы, которые её используют, поэтому, вместо этого, когда мне нужно протестировать новый экземпляр winmm, я просто переименовывая winmm.dll в winmm.old, копирую новый экземпляр и перезагружаю машину (прим. пер.: если проверять нужно в новом приложении, то перезагружать не обязательно - LoadLibrary загрузит именно новую копию).

Читать далее.

Комментариев нет:

Отправить комментарий

Можно использовать некоторые HTML-теги, например:

<b>Жирный</b>
<i>Курсив</i>
<a href="http://www.example.com/">Ссылка</a>

Вам необязательно регистрироваться для комментирования - для этого просто выберите из списка "Анонимный" (для анонимного комментария) или "Имя/URL" (для указания вашего имени и ссылки на сайт). Все прочие варианты потребуют от вас входа в вашу учётку.

Пожалуйста, по возможности используйте "Имя/URL" вместо "Анонимный". URL можно просто не указывать.

Ваше сообщение может быть помечено как спам спам-фильтром - не волнуйтесь, оно появится после проверки администратором.

Примечание. Отправлять комментарии могут только участники этого блога.