Pull to refresh

Comments 29

Очень интересная особенность оказалась.
UFO just landed and posted this here
Посмотрите его первую статью http://habrahabr.ru/post/260133/
Там автор довольно неплохо скомпилил nginx для хорошей работе на Windows с блэкджеком и шлюзами
А может кто-нибудь проверить — есть ли и в исходниках для *nix похожая функция ngx_linux_check_filename?
На хабре есть isysoev — возможно он что-нибудь прокомментирует?
ngx_open_file в *nix-ах это define на стандартный open
#define ngx_open_file(name, mode, create, access)  \
   open((const char *) name, mode|create|O_BINARY, access)
Но там полно другого чего, например подозреваю что директивы типа «disable_symlinks» могут натянуть ручник на некоторых FS.
Хотя в *nix-ах он получше оттестирован, хотя бы из-за его распространенности.
В стандартных файловых системах Линукса, к счастью, нет способа обратиться к файлу миллионами разных способов, поэтому нет и необходимости в ngx_linux_check_filename().
В стандартных файловых системах Линукса, к счастью, нет способа обратиться к файлу миллионами разных способов, поэтому нет и необходимости в ngx_linux_check_filename().
К сожалению, таким образом (т.е. полностью) не стоит убирать эту проверку, чтобы исключить доступ к файлам по коротким именам 8.3 (вида «testpa~1/testfi~2.gif»),


А можете пояснить для чайников, зачем эта проверка вообще нужна?
Конкретно доступ к файлу под коротким именем? Думается, чтобы исключить перебор (типа брута и т.д.).
В принципе по той же причине, по какой выключают directory listing.
Я просто в целом логику работы не понимаю в данном случае.

находим в [src]\os\win32\ngx_files.c функцию ngx_open_file, которая только в случае успешного открытия файла (а мы помним про быстрый 404), вызывает другую функцию ngx_win32_check_filename (проверка легальности имени файла).


Т.е. мы сначала открываем файл, и, если операция успешна, проверяем длинное имя. Зачем? Что должно дальше происходить по результатам этой проверки?

P.S. Btw, генерация 8.3 имен в винде отключается. Может, просто имеет смысл включить это в системные требования к установке и не париться с проверкой?
Например, в такой конфигурации
location /authorization/ {
   auth_basic ...
   fastcgi_pass  ...
}

запрос "/author~1/script.php" не будет обработан в этом location'е.
Поэтому разрешаются только обращения по полному имени.
Несколько оффтопик, но меня ужасно интересует — в чем необходимость именно такой связки nginx-win? Именно не для тестирования а реальные use cases.
Именно такой, это какой?
Если это намек в сторону IIS, appache или любимое подставить, то у меня будет встречный вопрос «Когда оне будут такие же шустрые, динамичные и гибкие (во всех смыслах) как nginx?»
Т.е. для реального use case с преф-ом и девочками, а не поиграться и не для портала на 10 человек аля sharepoint?

Я беру nginx не потому, что он есть под linux — а потому-что он nginx. И не беру IIS, потому что он IIS.
Про nginx более-менее понятно. Непонятно 2 часть. Почему тогда Windows? Или nginx сервает ASP?
Сейчас кстати ASP.NET сервается хорошо и из под Линукса. У самого такой сетап.
Потому что не сам себе режиссер. Например, в корпоративном секторе от виндовс часто тупо никуда не деться.
Или nginx сервает ASP?
Что во фразе «и не беру IIS» было не понятно…
«Видимо Максим когда делал эту проверку не знал (ваш покорный слуга кстати тоже), что Windows возвращает длинное имя файла рекурсивно, т.е. для каждого подкаталога (и как видим эта информация не кэшируется в OS).»
Кстати, а где вы это узнали? Msdn, судя по всему, молчит по этому поводу.
Или методом «Для пробы закомментируем эту проверку...»?
Загляните под спойлер, где процесс-мониторинг.
Прочитал статью не заглянув туда. Действительно, не очевидное поведение системы, хотя логичное в данном случае.
И вы натолкнули меня на мысль проверить кое-что.
Являюсь пользователем Qt как для домашних так и для рабочих проектов уже около 4 лет, иногда даже принимают мои патчи.
Данный системный вызов(«GetLongPathName») используется так же в основном модуле библиотеки при возврата пути к папки в которой система по-умолчанию хранит временные файлы, упущу некоторый код, в общем это:

QString QFileSystemEngine::tempPath()
{
QString ret;
wchar_t tempPath[MAX_PATH];
const DWORD len = GetTempPath(MAX_PATH, tempPath);
if (len) { // GetTempPath() can return short names, expand.
wchar_t longTempPath[MAX_PATH];
const DWORD longLen = GetLongPathName(tempPath, longTempPath, MAX_PATH);
ret = longLen && longLen < MAX_PATH?
QString::fromWCharArray(longTempPath, longLen):
QString::fromWCharArray(tempPath, len);
}

}

То есть при каждом вызове данной функции будет вызываться GetLongPathName().
Потом почитал в каких случаях GetTempPath() возвращает «короткий» путь, оказывается в XP и то иногда нет(?) путь действительно возвращается «короткий», почему так делалось можно почитать в относительно старой статьи в достаточно известном блоге — http://blogs.msdn.com/b/oldnewthing/archive/2004/12/24/331750.aspx
В Windows > XP этот путь возвращается полный. Отчего при каждом вызове данного метода вызываем не нужный достаточно медленный системный вызов.

Потому добавив код:

wchar_t * pwc = wcschr(tempPath, L'~');
if (pwc) { // GetTempPath() can return short names, expand.
wchar_t longTempPath[MAX_PATH];
const DWORD longLen = GetLongPathName(tempPath, longTempPath, MAX_PATH);
ret = longLen && longLen < MAX_PATH?
QString::fromWCharArray(longTempPath, longLen):
QString::fromWCharArray(tempPath, len);
}
else {
ret = QString::fromWCharArray(tempPath, len);
}

И погоняв несколько бенчмарков выяснилось что в среднем прирост скорости до 5 раз.
На выходных оформлю патчик и кину на кодревью в Qt для этого случая и в пару других мест в коде.

P.S. Теги не пашут, нет кармы чтобы нормально код оформить.
Нельзя так делать.
Ответ почему — в том же блоге, что и заметка про TEMP: http://blogs.msdn.com/b/oldnewthing/archive/2004/04/14/113052.aspx
Ну да Novell, Windows NT etc. все еще рулят…
То, что баг трудновоспроизводим в современном окружении, вряд ли может быть оправданием для его игнорирования.
От того, что современная версия Windows называется «Windows 10», последняя не перестаёт быть наследницей Windows NT.
Спасибо за замечание. Очень жаль что так получается, надо почитать поразбиратсья с этим.
Прочитал эту заметку и, честно говоря, не понял почему так делать не нужно, особенно в случае когда берется значение этих системных переменных:
— The path specified by the TMP environment variable.
— The path specified by the TEMP environment variable.
— The path specified by the USERPROFILE environment variable.
— The Windows directory.

«Windows NT adds the hexadecimal hash overflow technique.» Что это за техника я тоже не понял и не нашел что-либо о ней.
Разве что действительно в редких случаях сети netware будут выдавать не полное имя файла… Судя по их сайту они вообще с 2005 года портируют свою система на Linux-based ядро.

Зато в мсдне написано как формируются 8.3 формат имени:
https://support.microsoft.com/en-us/kb/142982
и там еще внизу написано:
Applies to
Microsoft Windows Millennium Edition
Microsoft Windows 98 Standard Edition
Microsoft Windows 95
Microsoft Windows NT Server 4.0 Standard Edition
Microsoft Windows NT Workstation 4.0 Developer Edition

Так что считаю данное изменение имеет значение, особенно когда прирост в скорости не абстрактная величина, граничащая со случайностью, в 1.1 — 1.2 раза, а вполне себе в разы. Пока не сможете рассказать что имелось ввиду под «Windows NT adds the hexadecimal hash overflow technique.»
Уже сам нашел. https://usn.pw/blog/gen/2015/06/09/filenames/

The file extension is truncated to 3 characters, and (if longer than 8 characters) the file name is truncated to 6 characters followed by ~1. SomeStuff.aspx turns into SOMEST~1.ASP.
If these would cause a collision, ~2 is used instead, followed by ~3 and ~4.
Instead of going to ~5, the file name is truncated down to 2 characters, with the replaced replaced by a hexadecimal checksum of the long filename — SomeStuff.aspx turns into SOBC84~1.ASP, where BC84 is the result of the (previously-)undocumented checksum function.

То есть когда очень много одинаковых имен файлов в одной папке система будет резать часть имени и добавлять свой хеш чтобы вместиться в формат 8.3 с помощью недокументированной внутренней системной функции. В той статье как раз ее и пытаются найти, точнее нашли и разобрались как работает. Но все равно тильда будет.
Потому то и майкрософтовцы сами и советуют на виндо-серверах отключать генерацию 8.3 формата.
https://technet.microsoft.com/en-us/library/ff633453%28v=ws.10%29.aspx

Issue
In addition to the normal file names, the server is creating short, eight-character file names with a three-character file extension (8.3 file names) for all files.

Impact
Creating short file names in addition to the normal, long file names can significantly decrease file server performance.

Странно что по умолчанию не выключено. Хотя это критично лишь к файл-серверам.

Проверка на тильду — костыль и потенциальные грабли, не стоит так делать.
Её наличие в коротком пути в общем случае никто не гарантирует: http://blogs.msdn.com/b/oldnewthing/archive/2004/04/14/113052.aspx
Лучше, как советовали в комментариях выше, попробовать отключить генерацию 8.3: https://support.microsoft.com/en-us/kb/121007
Лучше, как советовали в комментариях выше, попробовать отключить генерацию 8.3
Во первых, отключить простите где? На хосте корпоративного клиента? С удовольствием посмотрю на то как вы там админов уговаривать будете…

Во вторых, «Windows Server 2008, Windows Vista, Windows Server 2003, and Windows XP: 8.3 aliasing cannot be disabled for specified volumes until Windows 7 and Windows Server 2008 R2.» Взято из Naming Files, Paths, and Namespaces (Windows)

В третих, одно другому совершенно не мешает.

Проверка на тильду — костыль и потенциальные грабли, не стоит так делать.
Вы вероятно имеете ввиду «Not all file systems follow the tilde substitution convention». Этой фразе 20-ть лет в обед исполняется. Ну и отключайте это для тех obscure-obsolete FS.

Кроме того перебор коротких путей без «tilde substitution convention» не имеет большого смысла.
А защита внутренних location (пример Игоря выше про php-скрипт) достигается совершенно другим способом: не нужно иметь глобальных location позволяющих вернуть любой файл системы. Это моветон.
Sign up to leave a comment.

Articles