diff --git a/notebook/services/contents/filemanager.py b/notebook/services/contents/filemanager.py index 7f445a8f71..b7ba7c5c7a 100644 --- a/notebook/services/contents/filemanager.py +++ b/notebook/services/contents/filemanager.py @@ -334,12 +334,20 @@ def _dir_model(self, path, content=True): self.log.debug("%s not a regular file", os_path) continue - if self.should_list(name): - if self.allow_hidden or not is_file_hidden(os_path, stat_res=st): - contents.append( - self.get(path='%s/%s' % (path, name), content=False) + try: + if self.should_list(name): + if self.allow_hidden or not is_file_hidden(os_path, stat_res=st): + contents.append( + self.get(path='%s/%s' % (path, name), content=False) + ) + except OSError as e: + # ELOOP: recursive symlink + if e.errno != errno.ELOOP: + self.log.warning( + "Unknown error checking if file %r is hidden", + os_path, + exc_info=True, ) - model['format'] = 'json' return model diff --git a/notebook/services/contents/tests/test_manager.py b/notebook/services/contents/tests/test_manager.py index 0e6b0fb2b2..371fb2a655 100644 --- a/notebook/services/contents/tests/test_manager.py +++ b/notebook/services/contents/tests/test_manager.py @@ -129,6 +129,26 @@ def test_bad_symlink(self): # broken symlinks should still be shown in the contents manager self.assertTrue('bad symlink' in contents) + @dec.skipif(sys.platform == 'win32') + def test_recursive_symlink(self): + with TemporaryDirectory() as td: + cm = FileContentsManager(root_dir=td) + path = 'test recursive symlink' + _make_dir(cm, path) + os_path = cm._get_os_path(path) + os.symlink("recursive", os.path.join(os_path, "recursive")) + file_model = cm.new_untitled(path=path, ext='.txt') + + model = cm.get(path) + + contents = { + content['name']: content for content in model['content'] + } + self.assertIn('untitled.txt', contents) + self.assertEqual(contents['untitled.txt'], file_model) + # recursive symlinks should not be shown in the contents manager + self.assertNotIn('recursive', contents) + @dec.skipif(sys.platform == 'win32' and sys.version_info[0] < 3) def test_good_symlink(self): with TemporaryDirectory() as td: