uso tamaño rutas ruta nombres más maximo mas limite largos largas habilitar eliminar cómo copiar como caracteres archivos windows winapi internals

rutas - tamaño maximo ruta windows



¿Qué sucede internamente cuando una ruta de archivo supera los aprox. 32767 caracteres en Windows? (1)

Como soy flojo, no escribí un programa de prueba pero lo probé usando el excelente Far Manager, que maneja cosas como rutas largas (más largas que MAX_PATH ) o nombres de archivo especiales ( con , prn , etc.) bien.

Hice una cadena de exactamente 255 caracteres ("12345678901234 ... 012345") y comencé a crear directorios anidados. Afortunadamente, la función "Hacer directorio" de Far toma una cadena separada por barras para indicar "crear directorios anidados", así que pude hacerlo en solo unos pocos pasos preparando una cadena en el editor interno con algunos copiar y pegar.

El camino más largo que pude crear tenía 32739 caracteres, contando desde "C: /" (es decir, no incluye "//? /" Agregado por Far). El error que recibo al intentar crear un directorio o archivo con solo un carácter adicional es " El nombre de archivo o la extensión es demasiado larga ". Si trato de ingresar a ese directorio, obtengo el mismo error.

EDITAR : pasó algún tiempo en el depurador y esto es lo que sucede en el nivel de la API de Win32:

  1. Intento crear un archivo con un personaje por encima del límite
  2. Far llama a CreateFileW con la cadena "//? / C: / 123 [...] 012345" que tiene 32744 caracteres de ancho (sin contar el cero de terminación).
  3. CreateFileW realiza algunas comprobaciones adicionales, convierte la cadena terminada en UNICODE_STRING en UNICODE_STRING (Length = 65488, MaximumLength = 65490) y prepara una estructura OBJECT_ATTRIBUTES .
  4. CreateFileW luego llama a NtCreateFile en ntdll.dll , que es solo un contenedor de instrucciones de syscall .
  5. NtCreateFile devuelve 0xC0000106 ( STATUS_NAME_TOO_LONG ).
  6. Ese valor de estado se convierte luego (usando RtlNtStatusToDosError ) al error 206 de Win32 ( ERROR_FILENAME_EXCED_RANGE ).

No me molesté en verificar qué sucede en el kernel, pero creo que también podría echarle un vistazo .

EDIT2 : ejecuté WinObj y encontré que en mi sistema C: es un enlace simbólico a /Device/HarddiskVolume1 . Esta cadena tiene 23 caracteres de largo. Si reemplazamos el /C: en la cadena pasada a NtCreateFile con él, obtenemos 32744 - 3 + 23 = 32764 caracteres. Junto con el cero de terminación, esto requiere 65530 bytes. Todavía está por debajo del límite (0xFFFF = 65535) así que supongo que se agrega algo extra, como una sesión o un nombre de espacio de nombres.

EDIT3 : después de pasar por el kernel:

  1. NtCreateFile llama a IopCreateFile
  2. IopCreateFile llama ObOpenObjectByName
  3. ObOpenObjectByName llama ObpLookupObjectName
  4. ObpLookupObjectName busca ObpDosDevicesShortNamePrefix ( "/??/" ) -> éxito
  5. omite el prefijo y divide la parte restante en "C:" y "/1234..."
  6. resuelve la "C:" con una llamada a ObpLookupDirectoryEntry
  7. luego llama a ObpParseSymbolicLink para pasarle la entrada del directorio _OBJECT_SYMBOLIC_LINK ( _OBJECT_SYMBOLIC_LINK con LinkTarget == "/Device/HarddiskVolume1" y DosDeviceDriveIndex == 3) y la parte restante del nombre.
  8. Luego hace algo como esto (fielmente reproducido por ReactOS ):

    TargetPath = &SymlinkObject->LinkTarget; TempLength = TargetPath->Length; TotalLength = TempLength + RemainingName->Length; if (LengthUsed > 0xFFF0) return STATUS_NAME_TOO_LONG;

    En nuestro caso, 46 ​​+ 65476 = 65522 (0xfff2) que está justo por encima del límite.

    Así que ahí, misterio resuelto (¡espero!).

PD todo probado en Windows 7 x64 SP1.

En Windows (suponga 2000 en adelante), una ruta de archivo puede tener como máximo aproximadamente 32767 caracteres de longitud. Esta limitación existe debido al manejo interno con UNICODE_STRING en la API nativa (también en el lado del kernel, en los controladores, etc.). Hasta aquí todo bien. Conozco la teoría detrás de esa parte.

La razón del límite es que los miembros Length y MaximumLength de UNICODE_STRING cuentan el número de bytes en el Buffer , pero son enteros de 16 bits sin signo.

También sé por qué el límite es una aproximación en lugar de un límite establecido. Esto se debe principalmente a cómo su nombre de archivo (por ejemplo, //./C:/boot.ini ) se resuelve a su forma nativa (por ejemplo, /??/C:/boot.ini ) y luego a algo que está prefijado por el nombre del dispositivo de volumen real y luego seguido de la ruta relativa a ese volumen, por ejemplo, /Device/HarddiskVolume2/boot.ini .

Además, desde el Explorador de Windows, el síntoma conocido cuando se MAX_PATH límite de MAX_PATH ("ANSI") es simular que el archivo o la carpeta no existe en algunas versiones de Windows (esto se corrigió en algún momento).

Pero lo que sucede en el gestor de objetos, el administrador de E / S y los niveles del controlador del sistema de archivos, respectivamente, cuando llamo CreateFile() con una ruta que se parece a //./C:/.../filename.ext y la ruta completa no lo hace exceda el límite, pero lo alcanza , en mi llamada a CreateFile() kernel32.dll y luego se expande? ...

Ni los SDK ni los WDK parecen ser especialmente habladores sobre el tema. ¿O miré en las secciones incorrectas?