Выбираем длинный путь (или прощай MAX_PATH)



Многим пользователям ПК под управлением ОС Windows, не говоря о разработчиках, знакомы проблемы при работе с длинными (более 260 символов, MAX_PATH) путями файлов или каталогов.

В данной статье рассматриваются способы избавления от этого пережитка при разработке приложений на различных платформах (WinApi, .Net Framework, .Net Core) и активации нативной поддержки длинных путей в Windows 10 (Anniversary Update).

Приложения Win API


В приложениях, которые используют Win API для работы с файлами, рецепт избавления от ограничения MAX_PATH был известен с незапамятных времён – необходимо было использовать Unicode версию функции с окончанием «W» для работы с директорией или файлом и начинать путь с префикса \\?\. Это давало возможность использовать пути длинной до 32767 символов.

В Windows 10 (1607) поведение функций для работы с файлами изменилось: появилась возможность отключить проверку ограничений MAX_PATH на уровне системы.

Это коснулось следующих функций:
Для работы с каталогами: CreateDirectoryW, CreateDirectoryExW, GetCurrentDirectoryW, RemoveDirectoryW, SetCurrentDirectoryW. И для работы с файлами: CopyFileW, CopyFile2, CopyFileExW, CreateFileW, CreateFile2, CreateHardLinkW, CreateSymbolicLinkW, DeleteFileW, FindFirstFileW, FindFirstFileExW, FindNextFileW, GetFileAttributesW, GetFileAttributesExW, SetFileAttributesW, GetFullPathNameW, GetLongPathNameW, MoveFileW, MoveFileExW, MoveFileWithProgressW, ReplaceFileW, SearchPathW, FindFirstFileNameW, FindNextFileNameW, FindFirstStreamW, FindNextStreamW, GetCompressedFileSizeW, GetFinalPathNameByHandleW.

Это избавляет от необходимости использовать префикса \\?\ и потенциально даёт шанс приложениям, работающим напрямую или косвенно через Win API, получить поддержку длинных путей без необходимости их пересборки. Как активировать эту возможность описано в конце статьи.

.Net Framework


Хотя .Net Framework и использует Win API для работы с файлами — предыдущее изменение не принесло бы результата, т.к. в код BCL встроены предварительные проверки на допустимость длинны имён каталогов и файлов, и до вызова функций Win API дело даже не доходило, выдавая известное исключение. По многочисленным просьбам сообщества (более 4500 на UserVoice) в версии 4.6.2 из кода BCL вырезали проверки ограничения длинны пути, отдав это на откуп операционной и файловой системам!

Вот что это даёт:
  • При использовании префикса “\\?\” мы можем работать с длинными путями как в Win API,
    Directory.CreateDirectory("\\\\?\\" + long_dir_name);
  • Если активировать нативную поддержку длинных имен файлов Windows 10 (1607), то даже не потребуется использовать префикс!

Как включить:
  • Использовать .Net Framework 4.6.2 как цель при сборке приложения.
  • Использовать конфигурационный файл, например, если приложение уже было собрано под .Net 4.0:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
    </startup>
  <runtime>
    <AppContextSwitchOverrides value="Switch.System.IO.UseLegacyPathHandling=false;Switch.System.IO.BlockLongPaths=false" />
  </runtime>
</configuration>


.Net Core


Тут поддержку длинных путей анонсировали ещё в ноябре 2015 года. Видимо сказалось Open Source природа проекта и отсутствие строгой необходимости обеспечения обратной совместимости.

Как включить:
Всё работает из коробки. В отличие от реализации в .Net Framework – тут нет необходимости в добавлении префикса “\\?\” – он добавляется автоматически при необходимости.

Вот тут можно посмотреть пример.

Как включить поддержку длинных путей в Windows 10 (1607)


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

Включить встроенную поддержку длинных путей можно создав или изменив следующий параметр системного реестра: HKLM\SYSTEM\CurrentControlSet\Control\FileSystem Параметр LongPathsEnabled (Тип: REG_DWORD) 1 – соответствует значению включено.



Или через групповые политики (Win+R\gpedit.msc) Computer Configuration > Administrative Templates > System > Filesystem > Enable NTFS long paths.Оно же в локализованном варианте: Конфигурация компьютера > Административные шаблоны > Система > Файловая система > Включить длинные пути Win32.



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

<application xmlns="urn:schemas-microsoft-com:asm.v3">
    <windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
        <ws2:longPathAware>true</ws2:longPathAware>
    </windowsSettings>
</application>

С CMD, к сожалению, это не сработает, на данный момент, из-за особенностей работы с путями, а в PowerShell должно всё заработать.

P.S.


На этом мой небольшой пятничный пост заканчивается, оставив за рамками вопросы полноты реализации поддержки длинных путей в Windows 10 (1607), или работоспособность при использовании различных комбинаций редакций Windows, файловых систем и API. По мере поступления новых фактов и результатов экспериментов пост будет обновляться.

Спасибо за внимание!
Share post
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 18

    +5
    Windows Registry Editor Version 5.00

    [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem]
    "LongPathsEnabled"=dword:00000001

      +4
      Круто, конечно. И настало счастье, всем, кроме тех 100500 программ, что уже скомпилированы с MAX_PATH = 260. :)
      • UFO just landed and posted this here
          +3
          Нет, я подумал об этом, но вспомнил, что во все эти функции надо передавать размер буфера.
            0
            Если манифест обязателен, то с безопасностью все должно быть пучком
              0
              Это не остановит народ от того, чтобы включать в программы примеры 20-летней давности. Беды особой нет, но и профита не будет.
              0
              А в чём, собственно, дыра? Если в приложении есть переполнение буфера при передаче длинного пути файла, то его можно использовать и без этого. Если оно срабатывает при попытке открытия реального файла с длинным путём, то такие файлы и пути и раньше можно было без проблем создать.
              0
              Надо думать это изначально была наша большая ошибка. Все WinAPI умеют работать с \\?\ путями со времён Win2k. В очень старой документации по WinAPI прямо в описании CreateFile чётко сказано, что начиная с WinNT, Unicode пути с приставкой \\?\ могут быть длиной 32000 символов. Не заметить этого можно было лишь читая документацию по диагонали. MAX_PATH это только для ANSI и DOS совместимости. Скрин той справки: https://yadi.sk/i/rN65fYVLtxKrn
                0
                Это даже в статье есть. Тем не менее, значительное количество примеров в интернетах основано именно на MAX_PATH. В основном потому, что это или кочующие примеры времён Win9x или написаны на их основе. Но реальность такова, что именно этот код навставляло себе приличное количество разработчиков. Да, они ССЗБ. Тем не менее.
              –3
              благими намерениями выстлана дорога в ад. Какую только полезную информацию пользователи не додумаются запихнуть в имена файлов и папок. В полном пути документа на файловой шаре может четыре раза содержаться имя компании, пару раз слово «NEW», и конечно, побольше плюсов, минусов, восклицательных знаков — как же без них.
              Единственным аргументом против этого безумия до сих пор оставались технические ограничения винды.
                +1
                Если каша у людей в голове, то нет границ безумию. Погрузите их в эпоху ДОС (8+3 — романтика...) — все равно найдут способы превратить в ад структуру каталогов.
                Если кто-то нарушает принятые в организации принципы именования папок и документов, подкиньте ему зацикленную символическую ссылку в качестве наказания.
                  0

                  Хочу по полемизировать с вашим комментарием, несмотря на то, что прошло уже 3 года.


                  Привычку запихивать в имена файлов и каталогов спецсимволы и ненужную информацию культивировал сам Микрософт. Для этого у него есть как минимум 2 папки с названиями Program Files и Program Files (x86), куда по умолчанию устанавливаются все программы.

                    –1
                    А где в Program Files спецсимволы? Неужели пробел?
                  +1
                  Натыкался всего несколько раз
                  1) при скачивании торнетов
                  2) при сохранении веб страниц
                  Может через пару лет проблему путей решат окончательно.
                    +1

                    Сталкивался этим при создании проекта ASP.NET Core — bower скачивает frontend-зависимости и пихает их в такое количество вложенных папок, что проводник Windows потом отказывается удалить папку с этим проектом.


                    Заголовок спойлера

                    \?\d:\Programming_WEB\xxxxxx\xxxxxx_old\xxxxxx\src\xxxxx\node_modules\grunt-contrib-less\node_modules\less\node_modules\request\node_modules\har-validator\node_modules\is-my-json-valid\node_modules\generate-object-property\node_modules\is_property...

                      0
                      Не вдавался в подробности, но проводник таки позволяет удалять такие папки. Ошибка возникает только если относительный путь превышает MAX_PATH. Т.е. можно зайти в предпоследнюю по вложенности папку и в ней все удалить, потом перейти выше и удалить еще… Если длина пути позволяет, можно даже с середины начинать.
                      Альтернативный способ — с помощью subst создать виртуальный диск, указывающий на папку, не лежащую в корне.
                        0
                        Такую структуру вроде убрали в NPM 3
                        0
                        кто работал с Autodesk Vault знает что это приложение создает рабочую папку на диске, вложенность структуры проектов может быть очень большая, но все упирается в ограничения файловой системы, при выдаче файла и превышении суммы папок и имен файлов, наступает кирдык, устраняемый только руками и переносом файлов вверх по структуре, может быть это будет в прошлом

                        Only users with full accounts can post comments. Log in, please.