%PDF- %PDF-
Direktori : /lib/python3/dist-packages/fs/ |
Current File : //lib/python3/dist-packages/fs/_ftp_parse.py |
from __future__ import absolute_import from __future__ import print_function from __future__ import unicode_literals import unicodedata import datetime import re import time from pytz import UTC from .enums import ResourceType from .permissions import Permissions EPOCH_DT = datetime.datetime.fromtimestamp(0, UTC) RE_LINUX = re.compile( r""" ^ ([ldrwx-]{10}) \s+? (\d+) \s+? ([\w\-]+) \s+? ([\w\-]+) \s+? (\d+) \s+? (\w{3}\s+\d{1,2}\s+[\w:]+) \s+ (.*?) $ """, re.VERBOSE, ) RE_WINDOWSNT = re.compile( r""" ^ (?P<modified_date>\S+) \s+ (?P<modified_time>\S+(AM|PM)?) \s+ (?P<size>(<DIR>|\d+)) \s+ (?P<name>.*) $ """, re.VERBOSE, ) def get_decoders(): """ Returns all available FTP LIST line decoders with their matching regexes. """ decoders = [ (RE_LINUX, decode_linux), (RE_WINDOWSNT, decode_windowsnt), ] return decoders def parse(lines): info = [] for line in lines: if not line.strip(): continue raw_info = parse_line(line) if raw_info is not None: info.append(raw_info) return info def parse_line(line): for line_re, decode_callable in get_decoders(): match = line_re.match(line) if match is not None: return decode_callable(line, match) return None def _parse_time(t, formats): for frmt in formats: try: _t = time.strptime(t, frmt) break except ValueError: continue else: return None year = _t.tm_year if _t.tm_year != 1900 else time.localtime().tm_year month = _t.tm_mon day = _t.tm_mday hour = _t.tm_hour minutes = _t.tm_min dt = datetime.datetime(year, month, day, hour, minutes, tzinfo=UTC) epoch_time = (dt - EPOCH_DT).total_seconds() return epoch_time def _decode_linux_time(mtime): return _parse_time(mtime, formats=["%b %d %Y", "%b %d %H:%M"]) 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 if is_link: name, _, _link_name = name.partition("->") name = name.strip() _link_name = _link_name.strip() permissions = Permissions.parse(perms[1:]) mtime_epoch = _decode_linux_time(mtime) name = unicodedata.normalize("NFC", name) raw_info = { "basic": {"name": name, "is_dir": is_dir}, "details": { "size": int(size), "type": int(ResourceType.directory if is_dir else ResourceType.file), }, "access": {"permissions": permissions.dump()}, "ftp": {"ls": line}, } access = raw_info["access"] details = raw_info["details"] if mtime_epoch is not None: details["modified"] = mtime_epoch access["user"] = uid access["group"] = gid return raw_info def _decode_windowsnt_time(mtime): return _parse_time(mtime, formats=["%d-%m-%y %I:%M%p", "%d-%m-%y %H:%M"]) def decode_windowsnt(line, match): """ Decodes a Windows NT FTP LIST line like one of these: `11-02-18 02:12PM <DIR> images` `11-02-18 03:33PM 9276 logo.gif` Alternatively, the time (02:12PM) might also be present in 24-hour format (14:12). """ is_dir = match.group("size") == "<DIR>" raw_info = { "basic": { "name": match.group("name"), "is_dir": is_dir, }, "details": { "type": int(ResourceType.directory if is_dir else ResourceType.file), }, "ftp": {"ls": line}, } if not is_dir: raw_info["details"]["size"] = int(match.group("size")) modified = _decode_windowsnt_time( match.group("modified_date") + " " + match.group("modified_time") ) if modified is not None: raw_info["details"]["modified"] = modified return raw_info