Skip to content

Commit

Permalink
Merge 7f76454 into 4efe083
Browse files Browse the repository at this point in the history
  • Loading branch information
althonos committed Mar 26, 2021
2 parents 4efe083 + 7f76454 commit f16188a
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 32 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Expand Up @@ -25,7 +25,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
test suites.
- `FSTestCases` now builds the large data required for `upload` and `download` tests only
once in order to reduce the total testing time.
- `MemoryFS.move` and `MemoryFS.movedir` will now avoid copying data.
- `MemoryFS.move` and `MemoryFS.movedir` will now avoid copying data.
Closes [#452](https://github.com/PyFilesystem/pyfilesystem2/issues/452).

### Fixed
Expand All @@ -36,6 +36,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Avoid creating a new connection on every call of `FTPFS.upload`. Closes [#455](https://github.com/PyFilesystem/pyfilesystem2/issues/455).
- `WrapReadOnly.removetree` not raising a `ResourceReadOnly` when called. Closes [#468](https://github.com/PyFilesystem/pyfilesystem2/issues/468).
- `WrapCachedDir.isdir` and `WrapCachedDir.isfile` raising a `ResourceNotFound` error on non-existing path ([#470](https://github.com/PyFilesystem/pyfilesystem2/pull/470)).
- `FTPFS` not listing certain entries with sticky/SUID/SGID permissions set by Linux server ([#473](https://github.com/PyFilesystem/pyfilesystem2/pull/473)).
Closes [#451](https://github.com/PyFilesystem/pyfilesystem2/issues/451).


## [2.4.12] - 2021-01-14
Expand Down
11 changes: 6 additions & 5 deletions fs/_ftp_parse.py
Expand Up @@ -19,7 +19,8 @@
RE_LINUX = re.compile(
r"""
^
([ldrwx-]{10})
([-dlpscbD])
([r-][w-][xsS-][r-][w-][xsS-][r-][w-][xtT-][\.\+]?)
\s+?
(\d+)
\s+?
Expand Down Expand Up @@ -110,14 +111,14 @@ def _decode_linux_time(mtime):


def decode_linux(line, match):
perms, links, uid, gid, size, mtime, name = match.groups()
is_link = perms.startswith("l")
is_dir = perms.startswith("d") or is_link
ty, perms, links, uid, gid, size, mtime, name = match.groups()
is_link = ty == "l"
is_dir = ty == "d" or is_link
if is_link:
name, _, _link_name = name.partition("->")
name = name.strip()
_link_name = _link_name.strip()
permissions = Permissions.parse(perms[1:])
permissions = Permissions.parse(perms)

mtime_epoch = _decode_linux_time(mtime)

Expand Down
146 changes: 120 additions & 26 deletions tests/test_ftp_parse.py
@@ -1,5 +1,6 @@
from __future__ import unicode_literals

import textwrap
import time
import unittest

Expand Down Expand Up @@ -33,23 +34,25 @@ def test_parse_time(self, mock_localtime):
self.assertEqual(ftp_parse._parse_time("notadate", formats=["%b %d %Y"]), None)

def test_parse(self):
self.assertEqual(ftp_parse.parse([""]), [])
self.assertListEqual(ftp_parse.parse([""]), [])

def test_parse_line(self):
self.assertIs(ftp_parse.parse_line("not a dir"), None)

@mock.patch("time.localtime")
def test_decode_linux(self, mock_localtime):
mock_localtime.return_value = time2017
directory = """\
lrwxrwxrwx 1 0 0 19 Jan 18 2006 debian -> ./pub/mirror/debian
drwxr-xr-x 10 0 0 4096 Aug 03 09:21 debian-archive
lrwxrwxrwx 1 0 0 27 Nov 30 2015 debian-backports -> pub/mirror/debian-backports
drwxr-xr-x 12 0 0 4096 Sep 29 13:13 pub
-rw-r--r-- 1 0 0 26 Mar 04 2010 robots.txt
drwxr-xr-x 8 foo bar 4096 Oct 4 09:05 test
drwxr-xr-x 2 foo-user foo-group 0 Jan 5 11:59 240485
"""
directory = textwrap.dedent(
"""
lrwxrwxrwx 1 0 0 19 Jan 18 2006 debian -> ./pub/mirror/debian
drwxr-xr-x 10 0 0 4096 Aug 03 09:21 debian-archive
lrwxrwxrwx 1 0 0 27 Nov 30 2015 debian-backports -> pub/mirror/debian-backports
drwxr-xr-x 12 0 0 4096 Sep 29 13:13 pub
-rw-r--r-- 1 0 0 26 Mar 04 2010 robots.txt
drwxr-xr-x 8 foo bar 4096 Oct 4 09:05 test
drwxr-xr-x 2 foo-user foo-group 0 Jan 5 11:59 240485
"""
)

expected = [
{
Expand Down Expand Up @@ -158,25 +161,27 @@ def test_decode_linux(self, mock_localtime):
},
]

parsed = ftp_parse.parse(directory.splitlines())
self.assertEqual(parsed, expected)
parsed = ftp_parse.parse(directory.strip().splitlines())
self.assertListEqual(parsed, expected)

@mock.patch("time.localtime")
def test_decode_windowsnt(self, mock_localtime):
mock_localtime.return_value = time2017
directory = """\
unparsable line
11-02-17 02:00AM <DIR> docs
11-02-17 02:12PM <DIR> images
11-02-17 02:12PM <DIR> AM to PM
11-02-17 03:33PM 9276 logo.gif
05-11-20 22:11 <DIR> src
11-02-17 01:23 1 12
11-02-17 4:54 0 icon.bmp
11-02-17 4:54AM 0 icon.gif
11-02-17 4:54PM 0 icon.png
11-02-17 16:54 0 icon.jpg
"""
directory = textwrap.dedent(
"""
unparsable line
11-02-17 02:00AM <DIR> docs
11-02-17 02:12PM <DIR> images
11-02-17 02:12PM <DIR> AM to PM
11-02-17 03:33PM 9276 logo.gif
05-11-20 22:11 <DIR> src
11-02-17 01:23 1 12
11-02-17 4:54 0 icon.bmp
11-02-17 4:54AM 0 icon.gif
11-02-17 4:54PM 0 icon.png
11-02-17 16:54 0 icon.jpg
"""
)
expected = [
{
"basic": {"is_dir": True, "name": "docs"},
Expand Down Expand Up @@ -230,5 +235,94 @@ def test_decode_windowsnt(self, mock_localtime):
},
]

parsed = ftp_parse.parse(directory.splitlines())
parsed = ftp_parse.parse(directory.strip().splitlines())
self.assertEqual(parsed, expected)

@mock.patch("time.localtime")
def test_decode_linux_suid(self, mock_localtime):
# reported in #451
mock_localtime.return_value = time2017
directory = textwrap.dedent(
"""
drwxr-sr-x 66 ftp ftp 8192 Mar 16 17:54 pub
-rw-r--r-- 1 ftp ftp 25 Mar 18 19:34 robots.txt
"""
)
expected = [
{
"access": {
"group": "ftp",
"permissions": [
"g_r",
"g_s",
"o_r",
"o_x",
"u_r",
"u_w",
"u_x",
],
"user": "ftp",
},
"basic": {"is_dir": True, "name": "pub"},
"details": {"modified": 1489686840.0, "size": 8192, "type": 1},
"ftp": {
"ls": "drwxr-sr-x 66 ftp ftp 8192 Mar 16 17:54 pub"
},
},
{
"access": {
"group": "ftp",
"permissions": [
"g_r",
"o_r",
"u_r",
"u_w",
],
"user": "ftp",
},
"basic": {"is_dir": False, "name": "robots.txt"},
"details": {"modified": 1489865640.0, "size": 25, "type": 2},
"ftp": {
"ls": "-rw-r--r-- 1 ftp ftp 25 Mar 18 19:34 robots.txt"
},
},
]

parsed = ftp_parse.parse(directory.strip().splitlines())
self.assertListEqual(parsed, expected)

@mock.patch("time.localtime")
def test_decode_linux_sticky(self, mock_localtime):
# reported in #451
mock_localtime.return_value = time2017
directory = textwrap.dedent(
"""
drwxr-xr-t 66 ftp ftp 8192 Mar 16 17:54 pub
"""
)
expected = [
{
"access": {
"group": "ftp",
"permissions": [
"g_r",
"g_x",
"o_r",
"o_t",
"u_r",
"u_w",
"u_x",
],
"user": "ftp",
},
"basic": {"is_dir": True, "name": "pub"},
"details": {"modified": 1489686840.0, "size": 8192, "type": 1},
"ftp": {
"ls": "drwxr-xr-t 66 ftp ftp 8192 Mar 16 17:54 pub"
},
},
]

self.maxDiff = None
parsed = ftp_parse.parse(directory.strip().splitlines())
self.assertListEqual(parsed, expected)

0 comments on commit f16188a

Please sign in to comment.