#define MAX_PATH 260

Bis zum heutigen Tag habe ich selbst noch kein “System” so unglücklich zusammengebaut, dass ich damit die alt-bekannte maximale Pfadlänge von 260 Zeichen im Windows Dateisystem konzeptionell überschritten hätte.

Aber nachdem ich berufsbedingt ja immer wieder mal mit CONAN arbeiten darf/muss, bekommen diese Grenzwerte nun auch für mich Bedeutung.


DOS, Win16 und Win32

Ein DOS Pfad (erkennbar an Laufwerksbuchstaben und Doppelpunkt am Anfang) besteht aus 3 Zeichen am Anfang um das Gerät zu beschreiben, dann bis zu 256 Zeichen für Verzeichnisse und Dateinamen und einem NULL-Zeichen als Terminator.

Das macht dann 260 Zeichen und damit wir in C ein lokales char-Array allokieren können um dort Pfade hineinzupuffern, stellt die <windows.h> das MAX_PATH Makro genau dafür bereit.

Das war unter DOS und Windows 3.x mehr als genug, denn mit den damals üblichen “8.3” Dateinamen kann man mit maximal 12 Zeichen pro Ebene + 1 Backslash mindestens 19 Unterverzeichnisebenen in so einem Pfad unterbringen.
Sind die Verzeichnisnamen kürzer, geht natürlich noch viel mehr.

Dass Win32 dieses Limit übernommen hat, scheint mir schon ein bisschen “dumm”, Dass MAX_PATH aus Kompatibilitätsgründen gleichbleiben muss, ist ja OK, aber dass die Windows-APIs die Längen von übergebenen Pfadpuffern prüfen und bei Überschreitung mit Fehlern abbrechen, das hätte nicht sein müssen. (Muss wohl so ein Windows 95-Erbe gewesen sein, das NT infiziert hat.)

Und so leben wir bis heute mit einem Limit von vor 30 Jahren, obwohl seit NT 4 Pfade bis 32000 Zeichen lang sein dürfen, diese müssen dann aber der NT-Nomenklatur folgen und dürfen nicht mit DOS-Laufwerksbuchstaben beginnen.

Die Katze beißt sich dann dummerweise in den Schwanz, wenn man das Spiel zwischen App- und OS-Entwicklern verfolgt:

Wenn User manuell einen NT-Pfad eintippen, z.B.: \\.\C:\Windows\System32\calc.exe und die App den String 1 zu 1 an die APIs übergeben würden, dann wäre alles OK.

Leider sind es dann Codes wie:

 1if(path[1] == ':') // <- expect DOS path
 2{
 3        // absolute path:
 4        open_path(path);
 5}
 6else
 7{
 8        // relative path:
 9        open_path(get_cwd() + path);
10}

die “künstlich” Fehler generieren, oder wenn am Ende wirklich ein TCHAR localpath[MAX_PATH]; die Pfadlänge limitiert.

GATE Limits

Tatsächlich ist die GATE Implementierung an vielen Stellen auch nicht perfekt, aber ich versuche die Limits weiter nach oben zu schrauben, wo es notwendig ist.

Aktuell schreibt ein GATE-Makro 3072 Zeichen als Maximale Grenze vor.

Warum das?

Nun, ich gehe davon aus, dass in einer Funktion durchschnittlich nicht mehr als 2 Dateipfade vorliegen, einmal Input und einmal Output.

Mit Windows-Unicodezeichen wären das dann 12288 Bytes. Damit bleiben weitere 4 KByte übrig bis die empfohlene Stack-Puffer-Grenze von 16 KByte für Funktionen erreicht wurde.

Würde man größere Puffer wie 4096 einsetzen, würden Code-Analyse Tools in den meisten Datei I/O Routinen davor warnen, den Stack zu schnell wachsen zu lassen.
Dieses Limit kann man natürlich beim Kompilieren anpassen, denn es stellt ein absolutes “Minimum” für alle Plattformen dar.

Generell wird auch so weit ich weiß unter Linux empfohlen, Pfade unter 1 KB Länge zu halten und 4 KB als Obergrenze anzusehen. Und bisher bin ich mit meinen 3 KB immer gut gefahren.

Das CONAN Problem

Build-Systeme wie CONAN nutzen Hashes als Unterverzeichnisse um ihre Buildumgebungen abzutrennen. Hat man nun viele Unterverzeichnisse im Sourcecode, summieren sich schnell Pfade über den 260 Zeichen auf.

Es gibt zwar die Einstellung short_paths, doch auch die kann dann nicht immer helfen.

Ärgerlich ist, dass man auch dieses Tool nicht dazu bringen kann, NT-Pfade für alle Operationen einzusetzen. Und somit muss man wieder Workarounds ausarbeiten um die Pfade künstlich kurz zu halten.

Auch Visual Studio und sein Build System haben zu langen Pfaden Probleme. Dabei wäre es so einfach mit einem vorangestellten \\.\ sämtliche Pfade längenunabhängig zu unterstützen.

Fazit

Windows 10 hat die 260 Zeichengrenze bereits fallen gelassen und die WinAPI frisst nun auch längere Parameter. Dennoch sind bei weitem nicht alle Apps in der Lage mit mehr als 260 Zeichen arbeiten zu können.

Und so lange in Frameworks der MAX_PATH auch nur ein einziges Mal vorkommt, so lange limitieren wir uns auf das vergangene Jahrhundert zurück.

Ich selbst werde das Thema Pfadpuffer aber auch noch mal angehen. Zwar bin ich mit 3K-chars fast 12x besser vorbereitet … aber “unabhängig” ist das eben auch nicht …

Es gibt also noch viel zu tun.