Por que o limite de 260 caracteres de comprimento de caminho existe no Windows?

Eu enfrentei este problema algumas vezes em momentos inoportunos:

  • tentando trabalhar em projetos Java de código aberto com caminhos profundos
  • Armazenando trees wiki do Fitnesse profundas no controle de origem
  • Um erro ao tentar usar o Bazaar para importar minha tree de controle de origem

Por que esse limite existe?

Por que ainda não foi removido?

Como você lida com o limite de caminho? … e não, mudar para o Linux ou Mac OS X não é uma resposta válida para esta pergunta;)

Citando este artigo http://msdn.microsoft.com/pt-br/library/aa365247(VS.85).aspx#maxpath

Limitação de Comprimento Máximo do Caminho

Na API do Windows (com algumas exceções discutidas nos parágrafos a seguir), o comprimento máximo de um caminho é MAX_PATH , que é definido como 260 caracteres. Um caminho local é estruturado na seguinte ordem: letra da unidade, dois-pontos, barra invertida, componentes de nome separados por barras invertidas e um caractere nulo de terminação. Por exemplo, o caminho máximo na unidade D é “D: \ alguns seqüência de caminho de 256 caracteres ” onde “” representa o caractere nulo de terminação invisível para a página de código do sistema atual. (Os caracteres <> são usados ​​aqui para clareza visual e não podem fazer parte de uma string de caminho válida.)

Agora vemos que é 1 + 2 + 256 + 1 ou [drive] [: \] [path] [null] = 260. Pode-se supor que 256 é um comprimento de string fixo razoável dos dias do DOS. E voltando às APIs do DOS, percebemos que o sistema rastreava o caminho atual por unidade e temos 26 (32 com símbolos) unidades máximas (e diretórios atuais).

O INT 0x21 AH = 0x47 diz “Esta function retorna a descrição do caminho sem a letra da unidade e a contrabarra inicial.” Assim, vemos que o sistema armazena o CWD como um par (drive, caminho) e você solicita o caminho especificando o drive (1 = A, 2 = B,…), se você especificar um 0, ele assumirá o caminho para a unidade retornada por INT 0x21 AH = 0x15 AL = 0x19. Então agora sabemos porque é 260 e não 256, porque esses 4 bytes não são armazenados na string do caminho.

Por que uma seqüência de caminho de 256 bytes, porque 640K é RAM suficiente.

Isso não é estritamente verdadeiro, pois o sistema de arquivos NTFS suporta caminhos de até 32k caracteres. Você pode usar a API do win32 e ” \\?\ ” Prefixo o caminho para usar mais de 260 caracteres.

Uma explicação detalhada do longo caminho do blog da equipe .Net BCL .
Um pequeno trecho destaca a questão dos longos caminhos

Outra preocupação é o comportamento inconsistente que resultaria da exposição do suporte a caminhos longos. Caminhos longos com o prefixo \\?\ Podem ser usados ​​na maioria das APIs do Windows relacionadas a arquivos, mas nem todas as APIs do Windows. Por exemplo, LoadLibrary, que mapeia um módulo para o endereço do processo de chamada, falha se o nome do arquivo for maior que MAX_PATH. Portanto, isso significa que MoveFile permitirá mover uma DLL para um local de modo que seu caminho tenha mais de 260 caracteres, mas quando você tentar carregar a DLL, ela falhará. Existem exemplos semelhantes em todas as APIs do Windows; Existem algumas soluções alternativas, mas elas estão em uma base caso a caso.

A questão é por que a limitação ainda existe. Certamente o Windows moderno pode aumentar o lado de MAX_PATH para permitir caminhos mais longos. Por que a limitação não foi removida?

  • O motivo pelo qual não pode ser removido é que o Windows prometeu que nunca mudaria.

Por meio do contrato de API, o Windows garantiu todos os aplicativos que as APIs de arquivo padrão nunca retornarão um caminho com mais de 260 caracteres.

Considere o seguinte código correto :

 WIN32_FIND_DATA findData; FindFileFirst("C:\Contoso\*", ref findData); 

O Windows garantiu meu programa que preencheria minha estrutura WIN32_FIND_DATA :

 WIN32_FIND_DATA { DWORD dwFileAttributes; FILETIME ftCreationTime; FILETIME ftLastAccessTime; FILETIME ftLastWriteTime; //... TCHAR cFileName[MAX_PATH]; //.. } 

Meu aplicativo não declarou o valor da constante MAX_PATH , a API do Windows fez. Meu aplicativo usou esse valor definido.

Minha estrutura está definida corretamente e só aloca 592 bytes no total. Isso significa que só posso receber um nome de arquivo com menos de 260 caracteres. O Windows me prometeu que se eu escrevesse meu aplicativo corretamente, meu aplicativo continuaria a funcionar no futuro.

Se o Windows permitisse nomes de arquivos com mais de 260 caracteres, meu aplicativo existente (que usava corretamente a API correta) falharia.

Para qualquer um que peça à Microsoft para alterar a constante MAX_PATH , primeiro eles precisam garantir que nenhum aplicativo existente falhe. Por exemplo, eu ainda possuo e uso um aplicativo do Windows que foi escrito para ser executado no Windows 3.11. Ele ainda roda no Windows 10. de 64 bits. É isso que a compatibilidade com versões anteriores oferece.

A Microsoft criou uma maneira de usar os 32.768 nomes de caminho completos; mas eles tiveram que criar um novo contrato de API para fazer isso. Por um lado, você deve usar a API do Shell para enumerar arquivos (como nem todos os arquivos existem em um disco rígido ou compartilhamento de rede).

Mas eles também não precisam quebrar aplicativos de usuários existentes. A grande maioria dos aplicativos não usa a API do shell para o trabalho de arquivos. Todo mundo apenas chama FindFirstFile / FindNextFile e chama um dia.

A partir do Windows 10. você pode remover a limitação modificando uma chave de registro.

Dica A partir do Windows 10, versão 1607, as limitações MAX_PATH foram removidas das funções comuns de arquivos e diretórios do Win32. No entanto, você deve aceitar o novo comportamento.

Uma chave de registro permite ativar ou desativar o novo comportamento de caminho longo. Para habilitar o comportamento de caminho longo, defina a chave do Registro em HKLM\SYSTEM\CurrentControlSet\Control\FileSystem LongPathsEnabled (Digite: REG_DWORD ). O valor da chave será armazenado em cache pelo sistema (por processo) após a primeira chamada para um arquivo Win32 afetado ou function de diretório (lista a seguir). A chave do registro não será recarregada durante a vida útil do processo. Para que todos os aplicativos no sistema reconheçam o valor da chave, uma reboot pode ser necessária porque alguns processos podem ter sido iniciados antes da chave ser definida. A chave do Registro também pode ser controlada por meio da Política de Grupo em Computer Configuration > Administrative Templates > System > Filesystem > Enable NTFS long paths . Você também pode ativar o novo comportamento de caminho longo por aplicativo por meio do manifesto:

   true   

Você pode montar uma pasta como uma unidade. Na linha de comando, se você tiver um caminho C:\path\to\long\folder você pode mapeá-lo para a letra de unidade X: usando:

 subst x: \path\to\long\folder 

Uma maneira de lidar com o limite de caminho é reduzir as inputs de caminho com links simbólicos.

Por exemplo:

  1. crie um diretório C:\p para manter links curtos para caminhos longos
  2. mklink /JC:\p\foo C:\Some\Crazy\Long\Path\foo
  3. adicione C:\p\foo ao seu caminho em vez do longo caminho

Quanto ao motivo pelo qual isso ainda existe – a MS não considera uma prioridade e valoriza a compatibilidade retroativa em relação ao avanço do sistema operacional (pelo menos nesta instância).

Uma solução alternativa que uso é usar os “nomes abreviados” para os diretórios no caminho, em vez de suas versões padrão legíveis por humanos. Então, por exemplo, para C:\Program Files\ eu usaria C:\PROGRA~1\ Você pode encontrar os equivalentes de nome curto usando dir /x .

Quanto a como lidar com a limitação do tamanho do caminho no Windows – usando o 7zip para empacotar (e descompactar) seus arquivos sensíveis ao tamanho do caminho parece uma solução viável. Eu usei-o para transportar várias instalações de IDE (aqueles caminhos de plug-in do Eclipse, yikes!) E pilhas de documentação gerada automaticamente e não tive um único problema até agora.

Não tenho certeza de como ele evita o limite de 260 caracteres definido pelo Windows (a partir de um PoV técnico), mas, ei, funciona!

Mais detalhes na página do SourceForge aqui :

“O NTFS pode realmente suportar nomes de caminho de até 32.000 caracteres de comprimento.”

O 7-zip também suporta nomes longos.

Mas está desativado no código SFX. Alguns usuários não gostam de caminhos longos, pois não entendem como trabalhar com eles. É por isso que o desativei no código SFX.

e notas de lançamento :

9,32 alfa 2013-12-01

  • Suporte aprimorado para nomes de caminho de arquivo com mais de 260 caracteres.

4,44 beta 2007-01-20

  • O 7-Zip agora suporta nomes de caminho de arquivo com mais de 260 caracteres.

NOTA IMPORTANTE: Para que isso funcione corretamente, você precisará especificar o caminho de destino diretamente na checkbox de diálogo “Extrair” do 7zip , em vez de arrastar e soltar os arquivos na pasta pretendida. Caso contrário, a pasta “Temp” será usada como um cache temporário e você retornará para a mesma limitação de 260 caracteres assim que o Windows Explorer começar a mover os arquivos para o “local de descanso final”. Veja as respostas a esta pergunta para mais informações.

Outra maneira de lidar com isso é usar o Cygwin, dependendo do que você deseja fazer com os arquivos (ou seja, se os comandos do Cygwin atendem às suas necessidades)

Por exemplo, permite copiar, mover ou renomear arquivos que nem o Windows Explorer pode. Ou, claro, lidar com o conteúdo deles como md5sum, grep, gzip, etc.

Também para programas que você está codificando, você poderia vinculá-los à DLL do Cygwin e permitiria que eles usassem caminhos longos (eu não testei isso)

Ele faz, e é um padrão por algum motivo, mas você pode facilmente substituí-lo com essa chave de registro:

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

Consulte: https://blogs.msdn.microsoft.com/jeremykuhne/2016/07/30/net-4-6-2-and-long-paths-on-windows-10/

Você pode habilitar nomes de caminho longos usando o PowerShell:

 Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem' -Name LongPathsEnabled -Type DWord -Value 1 

Outra versão é usar uma Política de Grupo em Computer Configuration / Administrative Templates / System / System Filesystem :

Editor de política de grupo

Enquanto todo mundo chora que 260 chars são horríveis em 2017, de alguma forma ninguém chora que a maioria das quebras de shitware gnu se encontra espaços em caminhos. Nem mesmo unicode. E falando de funções inerentemente quebradas – pense em seu strcpy favorito sem o n . Mesmo malloc é quebrado no linux porque ele depende de falhas de página para realmente confirmar o espaço de endereço reservado (que é lento e propenso a erros). Ninguém é perfeito e a ignorância não é uma razão válida para lamentar-se.

Além disso, os comentaristas de alguma forma não dizem o que exatamente está quebrado.

Existem 3 coisas que estão quebradas:

  • determinadas chamadas (só estou ciente de Get / SetCurrentDirectoryW) são limitadas a um único segmento e 260 caracteres, não importa o quê. Então caminhos essencialmente relativos são quebrados no Windows, emulá-los como você emula o fork se você for forçado a fazê-lo.

  • o software portado de não-windows que inerentemente se baseia em conceitos não-windows (incluindo o conceito de caminhos dir / relativos atuais, veja acima)

  • o software que é escrito do zero para o Windows, mas ainda usa uma API antiga (mas veja acima – enquanto há APIs para access geral ao sistema de arquivos, não há API para o diretório atual no Windows que funciona após MAX_PATH)

Quanto a porque ainda está quebrado – na minha opinião, a MS corrigiu tudo o que é consertável. Eu acho que é inheritance do diretório atual por processos filho que não permite que GetCurrentDirectoryW seja corrigido.