Многим пользователям ПК под управлением ОС 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. По мере поступления новых фактов и результатов экспериментов пост будет обновляться.

Спасибо за внимание!
Поделиться с друзьями
-->

Комментарии (16)


  1. a553
    05.08.2016 16:36
    +5

    Windows Registry Editor Version 5.00

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


  1. pda0
    05.08.2016 17:12
    +4

    Круто, конечно. И настало счастье, всем, кроме тех 100500 программ, что уже скомпилированы с MAX_PATH = 260. :)


    1. Ivan_83
      05.08.2016 18:08
      -2

      Всё значительно хуже.
      Сейчас человек предложил пропилить в системе дыру размером с пол системы.
      Это же в 100500 приложениях будет затёр стёк или куча/соседние параметры на ней.
      Притом часть приложений/библиотек системные, наверняка найдутся.

      Я бы таких советчиков-экспериментаторов посылал в лес.


      1. pda0
        05.08.2016 18:42
        +3

        Нет, я подумал об этом, но вспомнил, что во все эти функции надо передавать размер буфера.


      1. orcy
        05.08.2016 18:45

        Если манифест обязателен, то с безопасностью все должно быть пучком


        1. pda0
          05.08.2016 21:10

          Это не остановит народ от того, чтобы включать в программы примеры 20-летней давности. Беды особой нет, но и профита не будет.


      1. fedorro
        05.08.2016 20:54

        А в чём, собственно, дыра? Если в приложении есть переполнение буфера при передаче длинного пути файла, то его можно использовать и без этого. Если оно срабатывает при попытке открытия реального файла с длинным путём, то такие файлы и пути и раньше можно было без проблем создать.


    1. none7
      05.08.2016 20:13

      Надо думать это изначально была наша большая ошибка. Все WinAPI умеют работать с \\?\ путями со времён Win2k. В очень старой документации по WinAPI прямо в описании CreateFile чётко сказано, что начиная с WinNT, Unicode пути с приставкой \\?\ могут быть длиной 32000 символов. Не заметить этого можно было лишь читая документацию по диагонали. MAX_PATH это только для ANSI и DOS совместимости. Скрин той справки: https://yadi.sk/i/rN65fYVLtxKrn


      1. pda0
        05.08.2016 21:08

        Это даже в статье есть. Тем не менее, значительное количество примеров в интернетах основано именно на MAX_PATH. В основном потому, что это или кочующие примеры времён Win9x или написаны на их основе. Но реальность такова, что именно этот код навставляло себе приличное количество разработчиков. Да, они ССЗБ. Тем не менее.


  1. paratrooper5730
    05.08.2016 17:42
    -3

    благими намерениями выстлана дорога в ад. Какую только полезную информацию пользователи не додумаются запихнуть в имена файлов и папок. В полном пути документа на файловой шаре может четыре раза содержаться имя компании, пару раз слово «NEW», и конечно, побольше плюсов, минусов, восклицательных знаков — как же без них.
    Единственным аргументом против этого безумия до сих пор оставались технические ограничения винды.


    1. rrrav
      06.08.2016 16:59
      +1

      Если каша у людей в голове, то нет границ безумию. Погрузите их в эпоху ДОС (8+3 — романтика...) — все равно найдут способы превратить в ад структуру каталогов.
      Если кто-то нарушает принятые в организации принципы именования папок и документов, подкиньте ему зацикленную символическую ссылку в качестве наказания.


  1. Arxitektor
    05.08.2016 19:25
    +1

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


  1. Alex_ME
    05.08.2016 20:01
    +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...


    1. evnik
      06.08.2016 09:34

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


    1. acedened
      06.08.2016 19:17

      Такую структуру вроде убрали в NPM 3


  1. vovanza
    06.08.2016 16:21

    кто работал с Autodesk Vault знает что это приложение создает рабочую папку на диске, вложенность структуры проектов может быть очень большая, но все упирается в ограничения файловой системы, при выдаче файла и превышении суммы папок и имен файлов, наступает кирдык, устраняемый только руками и переносом файлов вверх по структуре, может быть это будет в прошлом