I just got burned by the 260 character path limitation in Windows. Why did Microsoft decided to limit paths to 3 characters for drive + 256 characters + 1 character for the terminator? Mac OS of the same vintage has a 31 character filename limit but no path limit since the FSSpec stored volume number, refnum, and 31 character filename (Pascal string as length byte + 31 characters). HFS running on 512k of RAM could support long paths, but Windows 3.1 and 95 cannot. Newer versions of Windows can under some limited circumstances break the 260 character path limit, but they are limited by compatibility to Win32 headers.
-
8Probably because they used fixed sized buffers to store things like the current working directory and 256 is a nice round number in binary. – Dec 10 '18 at 18:03
-
5Maximum path size actually supported by NTFS is much bigger (32,000 characters according to the first answer of this question.) 260 character limit is imposed by Windows API any can be easily by-passed with 3rd party software like Total Commander. – wizofwor Dec 11 '18 at 08:41
-
1The 32K limit only works with Unicode. For non-Unicode, the limit is 260. – cup Dec 11 '18 at 13:00
-
5The 32K limit is available in Unicode only, because Windows (NT-based, not Windows 95-based) is a Unicode (ok, UCS-2) Operating System, with an ANSI (ok, ASCII plus various 8-bits extensions like CP and MBCS) backward-compatibility layer for functionality that existed in Windows 95-based OSes. Long Paths are a Windows NT-only feature, and so to use it you need to step out of the 8-bit character set compatibility layer. – Euro Micelli Dec 11 '18 at 17:41
-
"260 characters should be enough for anyone." – Bruce Abbott Dec 11 '18 at 18:43
-
2Amazingly enough, the DOS LFN API (first exposed by Windows 95) theoretically supports paths longer than 260 characters... – Stephen Kitt Dec 11 '18 at 20:52
-
I'm wondering if the device path size (e.g. "A:/") plus the usual programmer default of char[256] is the reason ? 260 seems a little arbitrary.. – PaulHK Oct 27 '22 at 05:10
1 Answers
In the Windows world, the MAX_PATH 260-character limit dates back to the introduction of the Win32 APIs; it is for example documented in GetWindowsDirectory. Before that, Windows (at least in version 3) documented a 144-character limit; see for example GetSystemDirectory.
As far as why the path limit is 260 characters, the general answer you’ll find on the Internet is backwards compatibility. OK, that’s often the case in computing in general, and on Windows in particular (which is why many 30-year-old Windows programs can still be made to run on modern Windows, at least on 32-bit systems). The question then becomes, backwards compatibility with what?
The obvious answer would be DOS, and perhaps Win16. But DOS has a maximal path limit of 66 characters, constrained by its CDS (current directory structure) which has room for a 67-byte nul-terminated string to store each drive’s path (including drive letter, if appropriate). DOS-based versions of Windows couldn’t change this, since they had to maintain compatibility with DOS programs — imagine being able to store a file in a deeply-nested directory, only to have it be inaccessible from DOS! So the DOS limit doesn’t explain the 256-character limit in Win32. (I’m ignoring network drives here.)
(Incidentally, you can achieve the latter effect by mounting a FAT drive under Linux: Linux allows much longer paths on FAT than DOS or Windows can handle, so you can create directories which are so deeply nested that DOS can’t handle them properly.)
Digging further reveals something interesting; old Windows headers define, in stdlib.h,
#if defined(__OS2__) || defined(__WIN32__)
#define _MAX_PATH 260
#define _MAX_DRIVE 3
#define _MAX_DIR 256
#define _MAX_FNAME 256
#define _MAX_EXT 256
#else
#define _MAX_PATH 80
#define _MAX_DRIVE 3
#define _MAX_DIR 66
#define _MAX_FNAME 9
#define _MAX_EXT 5
#endif
The 80-byte MAX_PATH makes sense for DOS and Win16, based on the CDS above: that’s just enough room for a 66-byte path, \, 12-byte filename (11 bytes stored on disk and . separator), and a nul terminator.
The interesting part is the other definition: the famous 260-byte limit... defined for Win32, and for OS/2! Reading through the OS/2 APIs doesn’t help much, because they’re all designed to not have documented limits (programs are supposed to call DosQuerySysInfo with QSV_MAX_PATH_LENGTH to find the maximum path length), as are in fact most of the Windows APIs (e.g. GetCurrentDirectory which takes a buffer and allocated length, and indicates the required length if the buffer isn’t big enough). But Inside OS/2, in its description of the file system name space, says
All OS/2 filename and pathname interfaces, such as DosOpen, DosFindNext, and so on, are designed to take name strings of arbitrary length. Applications should use name buffers of at least 256 characters to ensure that a long name is not truncated.
So I get the impression that the 256-character limit is part of OS/2’s legacy, and that when it was chosen, 256 characters was considered sufficient for “name strings of arbitrary length”.
- 121,835
- 17
- 505
- 462
-
What I'd read for rationale early in the life of NT was that, though there was a pathname limit of 64K-1 bytes in the OS itself, it was deemed a requirement that application programmers could continue to allocate fixed-size string buffers, i.e., MAX_PATH needed to exist with some value. The specific value is just "seems reasonable". But that's NT when it became "Windows NT". I don't know whether the same limit applied while it was still "NT OS/2". – dave Dec 12 '18 at 13:08
-
I haven't read Windows header files in depth so the OS2 connection is news to me. I'm more familiar with the Unix and MacOS headers/interfaces which did not contain explicit limits on path length. However its worth pointing out that HFS did have a maximum filename length, but the data-structures to store file locations did not use paths at all. – Michael Shopsin Dec 12 '18 at 16:07
-
1Stephen, do you know why the heck it is possible to create a 252-character long file in C:\aaa\ (so the width of the full path will be 259 chars), but only a 255-character long file in C:\ (so the width of the full path will be 258 chars)? https://superuser.com/questions/1620259/the-maximum-length-of-the-path-of-a-file-259-or-258-characters – john c. j. Jan 25 '21 at 01:59
-
1Interestingly, DRDOS (up to DRDOS 6) used a different internal data structure for directories, with no limit on path length; it maintained a read-only copy of the CDS for compatibility's sake. It was eventually forced to switch to using the CDS 'for real' to improve compatibility with Windows 3.x; this change was released as an update disk for 6.0, and distributed as standard with 7.0 and later. – john_e Mar 18 '22 at 11:14
-
@StephenKitt: I notice a conflict of statements here: "buffers of at least 256 characters" and " the 256-character limit" - the former is a minimum, the latter is a maximum. Or? I do not refute your explanation at all, because it (kind of) makes sense. But still... :) Actually, it would make sense to think that the things were reversed: OS/2 made specific provisions to comply with the Windows limitation. So the OS/2 might have been the effect, not the cause. – virolino Mar 07 '23 at 12:28
-
1@virolino thanks for the interesting question! “buffers of at least 256 characters to ensure that a long name is not truncated” — that means that if you provide a buffer of 256 characters, long names won’t be truncated. Correct OS/2 code isn’t supposed to use
_MAX_PATHanyway, it’s supposed to callDosQuerySysInfo;_MAX_PATHis a compromise. Win32 came after OS/2, so OS/2 can’t be the effect... – Stephen Kitt Mar 07 '23 at 13:02 -
@StephenKitt: I am not at all familiar with the details. I just saw that OS/2 has overlapping history Windows family of OS's. I do not know when the lengths of the paths were decided, but based on the analysis of the data you provided (strictly) I got the feeling that I described above. Also, I made no claim about who uses what files and what data structures either. The text you quoted states clearly: minimum 256 characters. In Widows, it is maximum 256. So if OS/2 made the decision first, then Windows just fscked the compatibility with OS/2 - the opposite of "inherited"... – virolino Mar 07 '23 at 18:43
-
@StephenKitt: ... so, if Windows used OS/2 as the source of inspiration for the value of the number, it surely did not use the meaning of it. Just compare "_MAX_DIR" with "at least 256" - which means something like "_MIN_DIR". Just please do not get me wrong regarding the intention of my comment(s). I am not antagonizing you, I just want to understand better. I joined "Retrocomputing" just because your answer was so interesting ;) – virolino Mar 07 '23 at 18:49
-
@virolino on the contrary, I appreciate questions such as yours! You’re comparing two different things — buffer sizes and maximum path lengths. If a specification says that callers must provide a buffer of at least x bytes (or characters or whatever), absent any other considerations (such as errors indicating that the buffer is too small), that implies that the maximum returned length is x bytes: any returned value has to fit in the smallest “legal” buffer, x bytes in length. – Stephen Kitt Mar 08 '23 at 13:22
-
2@virolino put another way, if the maximum path length is x, then a buffer of size x is sufficient, but larger buffers can also be used. Again, on OS/2 this is all a compromise and probably there to allow developers used to writing
char buf[_MAX_PATH]to continue doing so; the OS/2 SDK was clear on the fact that programs were supposed to query the value at runtime. Win32 first appeared with Windows NT, and finding similarities at least in APIs between that and OS/2 isn’t surprising given NT’s development history. – Stephen Kitt Mar 08 '23 at 13:30 -
@StephenKitt: In many languages, allocating a buffer of a reasonable fixed size on the stack is easier and cheaper than having to allocate a buffer whose size won't be known until runtime, and for many tasks the benefits of being able to use longer path weren't worth the effort required to accommodate them. – supercat Mar 08 '23 at 16:45