@@ -124,6 +124,21 @@ def test_splitdrive(self):
124124 tester ('ntpath.splitdrive("//?/UNC/server/share/dir")' ,
125125 ("//?/UNC/server/share" , "/dir" ))
126126
127+ def test_splitdrive_invalid_paths (self ):
128+ self .assertEqual (ntpath .splitdrive ('\\ \\ ser\x00 ver\\ sha\x00 re\\ di\x00 r' ),
129+ ('\\ \\ ser\x00 ver\\ sha\x00 re' , '\\ di\x00 r' ))
130+ self .assertEqual (ntpath .splitdrive (b'\\ \\ ser\x00 ver\\ sha\x00 re\\ di\x00 r' ),
131+ (b'\\ \\ ser\x00 ver\\ sha\x00 re' , b'\\ di\x00 r' ))
132+ self .assertEqual (ntpath .splitdrive ("\\ \\ \udfff \\ \udffe \\ \udffd " ),
133+ ('\\ \\ \udfff \\ \udffe ' , '\\ \udffd ' ))
134+ if sys .platform == 'win32' :
135+ self .assertRaises (UnicodeDecodeError , ntpath .splitdrive , b'\\ \\ \xff \\ share\\ dir' )
136+ self .assertRaises (UnicodeDecodeError , ntpath .splitdrive , b'\\ \\ server\\ \xff \\ dir' )
137+ self .assertRaises (UnicodeDecodeError , ntpath .splitdrive , b'\\ \\ server\\ share\\ \xff ' )
138+ else :
139+ self .assertEqual (ntpath .splitdrive (b'\\ \\ \xff \\ \xfe \\ \xfd ' ),
140+ (b'\\ \\ \xff \\ \xfe ' , b'\\ \xfd ' ))
141+
127142 def test_splitroot (self ):
128143 tester ("ntpath.splitroot('')" , ('' , '' , '' ))
129144 tester ("ntpath.splitroot('foo')" , ('' , '' , 'foo' ))
@@ -214,6 +229,21 @@ def test_splitroot(self):
214229 tester ('ntpath.splitroot(" :/foo")' , (" :" , "/" , "foo" ))
215230 tester ('ntpath.splitroot("/:/foo")' , ("" , "/" , ":/foo" ))
216231
232+ def test_splitroot_invalid_paths (self ):
233+ self .assertEqual (ntpath .splitroot ('\\ \\ ser\x00 ver\\ sha\x00 re\\ di\x00 r' ),
234+ ('\\ \\ ser\x00 ver\\ sha\x00 re' , '\\ ' , 'di\x00 r' ))
235+ self .assertEqual (ntpath .splitroot (b'\\ \\ ser\x00 ver\\ sha\x00 re\\ di\x00 r' ),
236+ (b'\\ \\ ser\x00 ver\\ sha\x00 re' , b'\\ ' , b'di\x00 r' ))
237+ self .assertEqual (ntpath .splitroot ("\\ \\ \udfff \\ \udffe \\ \udffd " ),
238+ ('\\ \\ \udfff \\ \udffe ' , '\\ ' , '\udffd ' ))
239+ if sys .platform == 'win32' :
240+ self .assertRaises (UnicodeDecodeError , ntpath .splitroot , b'\\ \\ \xff \\ share\\ dir' )
241+ self .assertRaises (UnicodeDecodeError , ntpath .splitroot , b'\\ \\ server\\ \xff \\ dir' )
242+ self .assertRaises (UnicodeDecodeError , ntpath .splitroot , b'\\ \\ server\\ share\\ \xff ' )
243+ else :
244+ self .assertEqual (ntpath .splitroot (b'\\ \\ \xff \\ \xfe \\ \xfd ' ),
245+ (b'\\ \\ \xff \\ \xfe ' , b'\\ ' , b'\xfd ' ))
246+
217247 def test_split (self ):
218248 tester ('ntpath.split("c:\\ foo\\ bar")' , ('c:\\ foo' , 'bar' ))
219249 tester ('ntpath.split("\\ \\ conky\\ mountpoint\\ foo\\ bar")' ,
@@ -226,6 +256,20 @@ def test_split(self):
226256 tester ('ntpath.split("c:/")' , ('c:/' , '' ))
227257 tester ('ntpath.split("//conky/mountpoint/")' , ('//conky/mountpoint/' , '' ))
228258
259+ def test_split_invalid_paths (self ):
260+ self .assertEqual (ntpath .split ('c:\\ fo\x00 o\\ ba\x00 r' ),
261+ ('c:\\ fo\x00 o' , 'ba\x00 r' ))
262+ self .assertEqual (ntpath .split (b'c:\\ fo\x00 o\\ ba\x00 r' ),
263+ (b'c:\\ fo\x00 o' , b'ba\x00 r' ))
264+ self .assertEqual (ntpath .split ('c:\\ \udfff \\ \udffe ' ),
265+ ('c:\\ \udfff ' , '\udffe ' ))
266+ if sys .platform == 'win32' :
267+ self .assertRaises (UnicodeDecodeError , ntpath .split , b'c:\\ \xff \\ bar' )
268+ self .assertRaises (UnicodeDecodeError , ntpath .split , b'c:\\ foo\\ \xff ' )
269+ else :
270+ self .assertEqual (ntpath .split (b'c:\\ \xff \\ \xfe ' ),
271+ (b'c:\\ \xff ' , b'\xfe ' ))
272+
229273 def test_isabs (self ):
230274 tester ('ntpath.isabs("foo\\ bar")' , 0 )
231275 tester ('ntpath.isabs("foo/bar")' , 0 )
@@ -333,6 +377,29 @@ def test_join(self):
333377 tester ("ntpath.join('D:a', './c:b')" , 'D:a\\ .\\ c:b' )
334378 tester ("ntpath.join('D:/a', './c:b')" , 'D:\\ a\\ .\\ c:b' )
335379
380+ def test_normcase (self ):
381+ normcase = ntpath .normcase
382+ self .assertEqual (normcase ('' ), '' )
383+ self .assertEqual (normcase (b'' ), b'' )
384+ self .assertEqual (normcase ('ABC' ), 'abc' )
385+ self .assertEqual (normcase (b'ABC' ), b'abc' )
386+ self .assertEqual (normcase ('\xc4 \u0141 \u03a8 ' ), '\xe4 \u0142 \u03c8 ' )
387+ expected = '\u03c9 \u2126 ' if sys .platform == 'win32' else '\u03c9 \u03c9 '
388+ self .assertEqual (normcase ('\u03a9 \u2126 ' ), expected )
389+ if sys .platform == 'win32' or sys .getfilesystemencoding () == 'utf-8' :
390+ self .assertEqual (normcase ('\xc4 \u0141 \u03a8 ' .encode ()),
391+ '\xe4 \u0142 \u03c8 ' .encode ())
392+ self .assertEqual (normcase ('\u03a9 \u2126 ' .encode ()),
393+ expected .encode ())
394+
395+ def test_normcase_invalid_paths (self ):
396+ self .assertEqual (ntpath .normcase ('abc\x00 def' ), 'abc\x00 def' )
397+ self .assertEqual (ntpath .normcase (b'abc\x00 def' ), b'abc\x00 def' )
398+ self .assertEqual (ntpath .normcase ('\udfff ' ), '\udfff ' )
399+ if sys .platform == 'win32' :
400+ path = b'ABC' + bytes (range (128 , 256 ))
401+ self .assertEqual (ntpath .normcase (path ), path .lower ())
402+
336403 def test_normpath (self ):
337404 tester ("ntpath.normpath('A//////././//.//B')" , r'A\B' )
338405 tester ("ntpath.normpath('A/./B')" , r'A\B' )
@@ -381,6 +448,21 @@ def test_normpath(self):
381448 tester ("ntpath.normpath('\\ \\ ')" , '\\ \\ ' )
382449 tester ("ntpath.normpath('//?/UNC/server/share/..')" , '\\ \\ ?\\ UNC\\ server\\ share\\ ' )
383450
451+ def test_normpath_invalid_paths (self ):
452+ normpath = ntpath .normpath
453+ self .assertEqual (normpath ('fo\x00 o' ), 'fo\x00 o' )
454+ self .assertEqual (normpath (b'fo\x00 o' ), b'fo\x00 o' )
455+ self .assertEqual (normpath ('fo\x00 o\\ ..\\ bar' ), 'bar' )
456+ self .assertEqual (normpath (b'fo\x00 o\\ ..\\ bar' ), b'bar' )
457+ self .assertEqual (normpath ('\udfff ' ), '\udfff ' )
458+ self .assertEqual (normpath ('\udfff \\ ..\\ foo' ), 'foo' )
459+ if sys .platform == 'win32' :
460+ self .assertRaises (UnicodeDecodeError , normpath , b'\xff ' )
461+ self .assertRaises (UnicodeDecodeError , normpath , b'\xff \\ ..\\ foo' )
462+ else :
463+ self .assertEqual (normpath (b'\xff ' ), b'\xff ' )
464+ self .assertEqual (normpath (b'\xff \\ ..\\ foo' ), b'foo' )
465+
384466 def test_realpath_curdir (self ):
385467 expected = ntpath .normpath (os .getcwd ())
386468 tester ("ntpath.realpath('.')" , expected )
@@ -420,10 +502,6 @@ def test_realpath_basic(self):
420502 d = drives .pop ().encode ()
421503 self .assertEqual (ntpath .realpath (d ), d )
422504
423- # gh-106242: Embedded nulls and non-strict fallback to abspath
424- self .assertEqual (ABSTFN + "\0 spam" ,
425- ntpath .realpath (os_helper .TESTFN + "\0 spam" , strict = False ))
426-
427505 @os_helper .skip_unless_symlink
428506 @unittest .skipUnless (HAVE_GETFINALPATHNAME , 'need _getfinalpathname' )
429507 def test_realpath_strict (self ):
@@ -434,8 +512,51 @@ def test_realpath_strict(self):
434512 self .addCleanup (os_helper .unlink , ABSTFN )
435513 self .assertRaises (FileNotFoundError , ntpath .realpath , ABSTFN , strict = True )
436514 self .assertRaises (FileNotFoundError , ntpath .realpath , ABSTFN + "2" , strict = True )
515+
516+ @unittest .skipUnless (HAVE_GETFINALPATHNAME , 'need _getfinalpathname' )
517+ def test_realpath_invalid_paths (self ):
518+ realpath = ntpath .realpath
519+ ABSTFN = ntpath .abspath (os_helper .TESTFN )
520+ ABSTFNb = os .fsencode (ABSTFN )
521+ path = ABSTFN + '\x00 '
522+ # gh-106242: Embedded nulls and non-strict fallback to abspath
523+ self .assertEqual (realpath (path , strict = False ), path )
437524 # gh-106242: Embedded nulls should raise OSError (not ValueError)
438- self .assertRaises (OSError , ntpath .realpath , ABSTFN + "\0 spam" , strict = True )
525+ self .assertRaises (OSError , realpath , path , strict = True )
526+ path = ABSTFNb + b'\x00 '
527+ self .assertEqual (realpath (path , strict = False ), path )
528+ self .assertRaises (OSError , realpath , path , strict = True )
529+ path = ABSTFN + '\\ nonexistent\\ x\x00 '
530+ self .assertEqual (realpath (path , strict = False ), path )
531+ self .assertRaises (OSError , realpath , path , strict = True )
532+ path = ABSTFNb + b'\\ nonexistent\\ x\x00 '
533+ self .assertEqual (realpath (path , strict = False ), path )
534+ self .assertRaises (OSError , realpath , path , strict = True )
535+ path = ABSTFN + '\x00 \\ ..'
536+ self .assertEqual (realpath (path , strict = False ), os .getcwd ())
537+ self .assertEqual (realpath (path , strict = True ), os .getcwd ())
538+ path = ABSTFNb + b'\x00 \\ ..'
539+ self .assertEqual (realpath (path , strict = False ), os .getcwdb ())
540+ self .assertEqual (realpath (path , strict = True ), os .getcwdb ())
541+ path = ABSTFN + '\\ nonexistent\\ x\x00 \\ ..'
542+ self .assertEqual (realpath (path , strict = False ), ABSTFN + '\\ nonexistent' )
543+ self .assertRaises (OSError , realpath , path , strict = True )
544+ path = ABSTFNb + b'\\ nonexistent\\ x\x00 \\ ..'
545+ self .assertEqual (realpath (path , strict = False ), ABSTFNb + b'\\ nonexistent' )
546+ self .assertRaises (OSError , realpath , path , strict = True )
547+
548+ path = ABSTFNb + b'\xff '
549+ self .assertRaises (UnicodeDecodeError , realpath , path , strict = False )
550+ self .assertRaises (UnicodeDecodeError , realpath , path , strict = True )
551+ path = ABSTFNb + b'\\ nonexistent\\ \xff '
552+ self .assertRaises (UnicodeDecodeError , realpath , path , strict = False )
553+ self .assertRaises (UnicodeDecodeError , realpath , path , strict = True )
554+ path = ABSTFNb + b'\xff \\ ..'
555+ self .assertRaises (UnicodeDecodeError , realpath , path , strict = False )
556+ self .assertRaises (UnicodeDecodeError , realpath , path , strict = True )
557+ path = ABSTFNb + b'\\ nonexistent\\ \xff \\ ..'
558+ self .assertRaises (UnicodeDecodeError , realpath , path , strict = False )
559+ self .assertRaises (UnicodeDecodeError , realpath , path , strict = True )
439560
440561 @os_helper .skip_unless_symlink
441562 @unittest .skipUnless (HAVE_GETFINALPATHNAME , 'need _getfinalpathname' )
@@ -847,6 +968,21 @@ def test_abspath(self):
847968 drive , _ = ntpath .splitdrive (cwd_dir )
848969 tester ('ntpath.abspath("/abc/")' , drive + "\\ abc" )
849970
971+ def test_abspath_invalid_paths (self ):
972+ abspath = ntpath .abspath
973+ self .assertEqual (abspath ('c:\\ fo\x00 o' ), 'c:\\ fo\x00 o' )
974+ self .assertEqual (abspath (b'c:\\ fo\x00 o' ), b'c:\\ fo\x00 o' )
975+ self .assertEqual (abspath ('c:\\ fo\x00 o\\ ..\\ bar' ), 'c:\\ bar' )
976+ self .assertEqual (abspath (b'c:\\ fo\x00 o\\ ..\\ bar' ), b'c:\\ bar' )
977+ self .assertEqual (abspath ('c:\\ \udfff ' ), 'c:\\ \udfff ' )
978+ self .assertEqual (abspath ('c:\\ \udfff \\ ..\\ foo' ), 'c:\\ foo' )
979+ if sys .platform == 'win32' :
980+ self .assertRaises (UnicodeDecodeError , abspath , b'c:\\ \xff ' )
981+ self .assertRaises (UnicodeDecodeError , abspath , b'c:\\ \xff \\ ..\\ foo' )
982+ else :
983+ self .assertEqual (abspath (b'c:\\ \xff ' ), b'c:\\ \xff ' )
984+ self .assertEqual (abspath (b'c:\\ \xff \\ ..\\ foo' ), b'c:\\ foo' )
985+
850986 def test_relpath (self ):
851987 tester ('ntpath.relpath("a")' , 'a' )
852988 tester ('ntpath.relpath(ntpath.abspath("a"))' , 'a' )
@@ -989,6 +1125,17 @@ def test_ismount(self):
9891125 self .assertTrue (ntpath .ismount (b"\\ \\ localhost\\ c$" ))
9901126 self .assertTrue (ntpath .ismount (b"\\ \\ localhost\\ c$\\ " ))
9911127
1128+ def test_ismount_invalid_paths (self ):
1129+ self .assertFalse (ntpath .ismount ("c:\\ \udfff " ))
1130+ if sys .platform == 'win32' :
1131+ self .assertRaises (ValueError , ntpath .ismount , "c:\\ \x00 " )
1132+ self .assertRaises (ValueError , ntpath .ismount , b"c:\\ \x00 " )
1133+ self .assertRaises (UnicodeDecodeError , ntpath .ismount , b"c:\\ \xff " )
1134+ else :
1135+ self .assertFalse (ntpath .ismount ("c:\\ \x00 " ))
1136+ self .assertFalse (ntpath .ismount (b"c:\\ \x00 " ))
1137+ self .assertFalse (ntpath .ismount (b"c:\\ \xff " ))
1138+
9921139 def test_isreserved (self ):
9931140 self .assertFalse (ntpath .isreserved ('' ))
9941141 self .assertFalse (ntpath .isreserved ('.' ))
@@ -1095,12 +1242,11 @@ def test_isjunction(self):
10951242 self .assertFalse (ntpath .isjunction ('tmpdir' ))
10961243 self .assertPathEqual (ntpath .realpath ('testjunc' ), ntpath .realpath ('tmpdir' ))
10971244
1098- @unittest .skipIf (sys .platform != 'win32' , "drive letters are a windows concept" )
1099- def test_isfile_driveletter (self ):
1100- drive = os .environ .get ('SystemDrive' )
1101- if drive is None or len (drive ) != 2 or drive [1 ] != ':' :
1102- raise unittest .SkipTest ('SystemDrive is not defined or malformed' )
1103- self .assertFalse (os .path .isfile ('\\ \\ .\\ ' + drive ))
1245+ def test_isfile_invalid_paths (self ):
1246+ self .assertIs (ntpath .isfile ('/tmp\udfff abcds' ), False )
1247+ self .assertIs (ntpath .isfile (b'/tmp\xff abcds' ), False )
1248+ self .assertIs (ntpath .isfile ('/tmp\x00 abcds' ), False )
1249+ self .assertIs (ntpath .isfile (b'/tmp\x00 abcds' ), False )
11041250
11051251 @unittest .skipUnless (hasattr (os , 'pipe' ), "need os.pipe()" )
11061252 def test_isfile_anonymous_pipe (self ):
@@ -1195,9 +1341,6 @@ def _check_function(self, func):
11951341
11961342 def test_path_normcase (self ):
11971343 self ._check_function (self .path .normcase )
1198- if sys .platform == 'win32' :
1199- self .assertEqual (ntpath .normcase ('\u03a9 \u2126 ' ), 'ωΩ' )
1200- self .assertEqual (ntpath .normcase ('abc\x00 def' ), 'abc\x00 def' )
12011344
12021345 def test_path_isabs (self ):
12031346 self ._check_function (self .path .isabs )
0 commit comments