Skip to content

Commit c5a5dae

Browse files
committed
Fixed handling of invalid parent paths in CreateDirectory()
- fixed handling of symlinks in MakeDirectories() - fixed exception thrown on too many symlinks - see #209
1 parent bc80ff8 commit c5a5dae

File tree

4 files changed

+29
-7
lines changed

4 files changed

+29
-7
lines changed

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ The release versions are PyPi releases.
1212
#### Infrastructure
1313

1414
#### Fixes
15+
* Incorrect error handling during directory creation ([#209](../../issues/209))
1516
* Creating files in read-only directory was possible ([#203](../../issues/203))
1617

1718
## [Version 3.2](https://pypi.python.org/pypi/pyfakefs/3.2)

fake_filesystem_test.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1471,7 +1471,24 @@ def testMakedirsRaisesIfParentIsFile(self):
14711471
directory = '%s/plugh' % file_path
14721472
self.filesystem.CreateFile(file_path)
14731473
self.assertTrue(self.filesystem.Exists(file_path))
1474-
self.assertRaises(Exception, self.os.makedirs, directory)
1474+
self.assertRaisesOSError(errno.ENOTDIR, self.os.makedirs, directory)
1475+
1476+
@unittest.skipIf(TestCase.is_windows and sys.version_info < (3, 3),
1477+
'Links are not supported under Windows before Python 3.3')
1478+
def testMakedirsRaisesIfParentIsBrokenLink(self):
1479+
link_path = '/broken_link'
1480+
self.os.symlink('bogus', link_path)
1481+
self.assertRaisesIOError(errno.ENOENT, self.os.makedirs, link_path + '/newdir')
1482+
1483+
@unittest.skipIf(TestCase.is_windows and sys.version_info < (3, 3),
1484+
'Links are not supported under Windows before Python 3.3')
1485+
def testMakedirsRaisesIfParentIsLoopingLink(self):
1486+
dir_path = '/foo/bar'
1487+
self.filesystem.CreateDirectory(dir_path)
1488+
link_target = dir_path + "/link"
1489+
link_path = link_target + "/link"
1490+
self.os.symlink(link_path, link_target)
1491+
self.assertRaisesOSError(errno.ELOOP, self.os.makedirs, link_path)
14751492

14761493
def testMakedirsRaisesIfAccessDenied(self):
14771494
"""makedirs raises exception if access denied."""
@@ -4201,9 +4218,8 @@ def testUtimeLink(self):
42014218
self.assertEqual(3, st.st_atime)
42024219
self.assertEqual(4, st.st_mtime)
42034220

4204-
@unittest.skipIf(TestCase.is_windows and sys.version_info < (3, 3),
4205-
'Links are not supported under Windows before Python 3.3')
42064221
def testTooManyLinks(self):
4222+
self.filesystem.is_windows_fs = False
42074223
self.filesystem.CreateLink('!a!loop', 'loop')
42084224
self.assertFalse(self.filesystem.Exists('!a!loop'))
42094225

pyfakefs/fake_filesystem.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1498,7 +1498,7 @@ def Exists(self, file_path):
14981498
return False
14991499
try:
15001500
file_path = self.ResolvePath(file_path)
1501-
except IOError:
1501+
except (IOError, OSError):
15021502
return False
15031503
if file_path == self.root.name:
15041504
return True
@@ -1638,7 +1638,7 @@ def _FollowLink(link_path_components, link):
16381638
# cycles.
16391639
link_depth += 1
16401640
if link_depth > _MAX_LINK_DEPTH:
1641-
raise IOError(errno.EMLINK,
1641+
raise OSError(errno.ELOOP,
16421642
'Too many levels of symbolic links: \'%s\'' %
16431643
_ComponentsToPath(resolved_components))
16441644
link_path = _FollowLink(resolved_components, current_dir)
@@ -1906,6 +1906,10 @@ def CreateDirectory(self, directory_path, perm_bits=PERM_DEF):
19061906
current_dir = new_dir
19071907
else:
19081908
current_dir = directory
1909+
if directory.st_mode & stat.S_IFLNK == stat.S_IFLNK:
1910+
current_dir = self.ResolveObject(directory.contents)
1911+
if directory.st_mode & stat.S_IFDIR != stat.S_IFDIR:
1912+
raise OSError(errno.ENOTDIR, 'Not a directory', current_dir.GetPath())
19091913

19101914
# set the permission after creating the directories
19111915
# to allow directory creation inside a read-only directory
@@ -2255,7 +2259,8 @@ def MakeDirectories(self, dir_name, mode=PERM_DEF, exist_ok=False):
22552259
# writeable.
22562260
current_dir = self.root
22572261
for component in path_components:
2258-
if component not in current_dir.contents:
2262+
if (component not in current_dir.contents
2263+
or not isinstance(current_dir.contents, list)):
22592264
break
22602265
else:
22612266
current_dir = current_dir.contents[component]

tox.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[tox]
2-
envlist=py26,py27,py33,py34,py35,py36,py37,pypy
2+
envlist=py26,py27,py33,py34,py35,py36
33

44
[testenv]
55
deps = -rrequirements.txt

0 commit comments

Comments
 (0)