diff --git a/README.md b/README.md index c98afe2..aab5e01 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ If you have an actual file on disk, you can get the most information possible When using a file on disk, the checks performed are: -* File type (file, symlink, directory, socket) +* File type (file, symlink, directory, socket, fifo) * Mode (is it executable?) * File name (mostly based on extension) * If executable, the shebang is read and the interpreter interpreted diff --git a/identify/identify.py b/identify/identify.py index 0279ba8..8064239 100644 --- a/identify/identify.py +++ b/identify/identify.py @@ -20,13 +20,14 @@ DIRECTORY = 'directory' SYMLINK = 'symlink' SOCKET = 'socket' +FIFO = 'fifo' FILE = 'file' EXECUTABLE = 'executable' NON_EXECUTABLE = 'non-executable' TEXT = 'text' BINARY = 'binary' -TYPE_TAGS = frozenset((DIRECTORY, FILE, SYMLINK, SOCKET)) +TYPE_TAGS = frozenset((DIRECTORY, FILE, SYMLINK, SOCKET, FIFO)) MODE_TAGS = frozenset((EXECUTABLE, NON_EXECUTABLE)) ENCODING_TAGS = frozenset((BINARY, TEXT)) _ALL_TAGS = {*TYPE_TAGS, *MODE_TAGS, *ENCODING_TAGS} @@ -50,6 +51,8 @@ def tags_from_path(path: str) -> set[str]: return {SYMLINK} if stat.S_ISSOCK(mode): return {SOCKET} + if stat.S_ISFIFO(mode): + return {FIFO} tags = {FILE} diff --git a/tests/identify_test.py b/tests/identify_test.py index a82f353..cabc6ba 100644 --- a/tests/identify_test.py +++ b/tests/identify_test.py @@ -20,6 +20,7 @@ def test_all_tags_includes_basic_ones(): assert 'executable' in identify.ALL_TAGS assert 'text' in identify.ALL_TAGS assert 'socket' in identify.ALL_TAGS + assert 'fifo' in identify.ALL_TAGS @pytest.mark.parametrize( @@ -110,6 +111,18 @@ def test_tags_from_path_file_with_shebang_executable(tmpdir): } +@pytest.mark.skipif(not hasattr(os, 'mkfifo'), reason='requires os.mkfifo') +@pytest.mark.parametrize('filename', ('pipe', 'pipe.py')) +@pytest.mark.parametrize('mode', (0o600, 0o700)) +def test_tags_from_path_fifo(tmpdir, filename, mode): + path = str(tmpdir.join(filename)) + os.mkfifo(path, mode) + # Reading a FIFO without a writer would block indefinitely. + error = AssertionError('opened FIFO') + with mock.patch('builtins.open', side_effect=error): + assert identify.tags_from_path(path) == {'fifo'} + + def test_tags_from_path_binary(tmpdir): x = tmpdir.join('test') x.write(b'\x7f\x45\x4c\x46\x02\x01\x01')