File: mergeall-products/unzipped/docetc/miscnotes/Windows-path-limits/windows-path-limits.py
#!/usr/bin/env python3
"""
--------------------------------------------------------------------------------
Isolate and verify the actual path-length limits on Windows.
See the corresponding output text file here for results.
Note that all paths here use _characters_, not bytes, strongly
sugggesting that length limits are not subject to any expansions
required for Unicode encodings.
Also note that relative path limits are _less_ than those of abs
paths, but correspond exactly to the lenth of their abs paths
forms (i.e., the lengths of the rel path + the CWD prefix). To
check lengths against the limits, code must use absolute paths.
--------------------------------------------------------------------------------
"""
import os, shutil
PREFIX = '\\\\?\\'
def TEST(root, rel=False):
def prefix(path):
if not rel:
return PREFIX + path
else:
return PREFIX + os.path.abspath(path)
#------------------------------------------------------------------------------
# DIRS
#------------------------------------------------------------------------------
print()
print('MAKE DIRS')
path = root
while True:
try:
path += 'x' # up to 255 for component > 247 dirpath limit
os.mkdir(path)
except:
print(' os.mkdir failed at len=%d chars' % len(path))
print('\tadding len=', end='')
for i in range(15):
print('%d ' % len(path), end='')
os.mkdir(prefix(path)) # add longer paths for more
path += 'x'
print()
break
print('ACCESS DIRS')
for func in(os.path.isdir, os.listdir, os.lstat):
path = root
while True:
try:
path += 'x'
res = func(path)
if res == False and func is os.path.isdir: # False on fail
raise OSError
except:
print(' %s failed at len=%d chars' %
(getattr(func, '__name__', func), len(path)))
break
print('ACCESS DIRS WITH PREFIX')
for func in(os.path.isdir, os.listdir, os.lstat):
path = root
while True:
try:
path += 'x'
res = func(prefix(path))
if res == False and func is os.path.isdir:
raise OSError
except:
print(' %s failed at len=%d chars' %
(getattr(func, '__name__', func), len(path)))
break
#------------------------------------------------------------------------------
# FILES
#------------------------------------------------------------------------------
print()
print('MAKE FILES')
path = root
while True:
try:
path += 'f'
f = open(path, 'w')
f.write('spam')
f.close()
except:
print(' open failed at len=%d chars' % len(path))
print('\tadding len=', end='')
for i in range(15):
print('%d ' % len(path), end='')
f = open(prefix(path), 'w')
f.write('spam')
f.close()
path += 'f'
print()
break
print('ACCESS FILES')
for func in(open, os.path.isfile, os.lstat):
path = root
while True:
try:
path += 'f'
res = func(path)
if res == False and func is os.path.isfile: # False on fail
raise OSError
except:
print(' %s failed at len=%d chars' %
(getattr(func, '__name__', func), len(path)))
break
print('ACCESS FILES WITH PREFIX')
for func in(open, os.path.isfile, os.lstat):
path = root
while True:
try:
path += 'f'
res = func(prefix(path))
if res == False and func is os.path.isfile: # False on fail
raise OSError
except:
print(' %s failed at len=%d chars' %
(getattr(func, '__name__', func), len(path)))
break
#------------------------------------------------------------------------------
# TEST ABSOLUTE PATHS (NOT REL)
#------------------------------------------------------------------------------
print()
print('ABSOLUTE PATHS', '*'*60)
root = 'C:\\Users\\mark\\Desktop\\dirlentest\\' # 33 chars here
if os.path.exists(root):
shutil.rmtree('\\\\?\\' + root) # clean up prior run's dirs
os.mkdir(root)
print('root prefix len=%d' % len(root))
TEST(root, rel=False)
#------------------------------------------------------------------------------
# REDO ALL WITH RELATIVE PATH (NOT ABS)
#------------------------------------------------------------------------------
print()
print('RELATIVE PATHS', '*'*60)
runin = 'C:\\Users\\mark\\Desktop'
os.chdir(runin)
root = 'dirlentest\\'
if os.path.exists(root):
shutil.rmtree('\\\\?\\' + os.path.abspath(root)) # clean up prior run
os.mkdir(root)
print('cwd len=%d (%d with \\)' % (len(runin), len(runin)+1))
print('root prefix len=%d' % len(root))
TEST(root, rel=True)