Skip to content

Commit 09cf4dc

Browse files
author
atollk
committed
Added support for MFMT command to FTPFS.setinfo to set the last modified time of a file.
1 parent 62d2de9 commit 09cf4dc

File tree

3 files changed

+47
-8
lines changed

3 files changed

+47
-8
lines changed

fs/copy.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,7 @@ def copy_mtime(
461461
dst_path (str): Path to a directory on the destination filesystem.
462462
463463
"""
464-
namespaces = ("details", "metadata_changed", "modified")
464+
namespaces = ("details",)
465465
with manage_fs(src_fs, writeable=False) as _src_fs:
466466
with manage_fs(dst_fs, create=True) as _dst_fs:
467467
src_meta = _src_fs.getinfo(src_path, namespaces)

fs/ftpfs.py

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import array
88
import calendar
9+
import datetime
910
import io
1011
import itertools
1112
import socket
@@ -19,8 +20,7 @@
1920
from ftplib import FTP_TLS
2021
except ImportError as err:
2122
FTP_TLS = err # type: ignore
22-
from ftplib import error_perm
23-
from ftplib import error_temp
23+
from ftplib import error_perm, error_temp
2424
from typing import cast
2525

2626
from six import PY2
@@ -836,8 +836,27 @@ def writebytes(self, path, contents):
836836

837837
def setinfo(self, path, info):
838838
# type: (Text, RawInfo) -> None
839-
if not self.exists(path):
840-
raise errors.ResourceNotFound(path)
839+
current_info = self.getinfo(path)
840+
if current_info.is_file and "MFMT" in self.features:
841+
mtime = 0.0
842+
if "modified" in info:
843+
mtime = float(cast(float, info["modified"]["modified"]))
844+
if "details" in info:
845+
mtime = float(cast(float, info["details"]["modified"]))
846+
if mtime:
847+
with ftp_errors(self, path):
848+
cmd = (
849+
"MFMT "
850+
+ datetime.datetime.fromtimestamp(mtime).strftime(
851+
"%Y%m%d%H%M%S"
852+
)
853+
+ " "
854+
+ _encode(path, self.ftp.encoding)
855+
)
856+
try:
857+
self.ftp.sendcmd(cmd)
858+
except error_perm:
859+
pass
841860

842861
def readbytes(self, path):
843862
# type: (Text) -> bytes

tests/test_ftpfs.py

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import time
1212
import unittest
1313
import uuid
14+
import datetime
1415

1516
try:
1617
from unittest import mock
@@ -144,7 +145,6 @@ def test_manager_with_host(self):
144145
@mark.slow
145146
@unittest.skipIf(platform.python_implementation() == "PyPy", "ftp unreliable with PyPy")
146147
class TestFTPFS(FSTestCases, unittest.TestCase):
147-
148148
user = "user"
149149
pasw = "1234"
150150

@@ -162,7 +162,7 @@ def setUpClass(cls):
162162
cls.server.shutdown_after = -1
163163
cls.server.handler.authorizer = DummyAuthorizer()
164164
cls.server.handler.authorizer.add_user(
165-
cls.user, cls.pasw, cls._temp_path, perm="elradfmw"
165+
cls.user, cls.pasw, cls._temp_path, perm="elradfmwT"
166166
)
167167
cls.server.handler.authorizer.add_anonymous(cls._temp_path)
168168
cls.server.start()
@@ -223,6 +223,27 @@ def test_geturl(self):
223223
),
224224
)
225225

226+
def test_setinfo(self):
227+
# TODO: temporary test, since FSTestCases.test_setinfo is broken.
228+
self.fs.create("bar")
229+
time1 = time.mktime(datetime.datetime.now().timetuple())
230+
time2 = time1 + 60
231+
self.fs.setinfo("bar", {"details": {"modified": time1}})
232+
mtime1 = self.fs.getinfo("bar", ("details",)).modified
233+
self.fs.setinfo("bar", {"details": {"modified": time2}})
234+
mtime2 = self.fs.getinfo("bar", ("details",)).modified
235+
replacement = {}
236+
if mtime1.microsecond == 0 or mtime2.microsecond == 0:
237+
mtime1 = mtime1.replace(microsecond=0)
238+
mtime2 = mtime2.replace(microsecond=0)
239+
if mtime1.second == 0 or mtime2.second == 0:
240+
mtime1 = mtime1.replace(second=0)
241+
mtime2 = mtime2.replace(second=0)
242+
mtime2_modified = mtime2.replace(minute=mtime2.minute - 1)
243+
self.assertEqual(
244+
mtime1.replace(**replacement), mtime2_modified.replace(**replacement)
245+
)
246+
226247
def test_host(self):
227248
self.assertEqual(self.fs.host, self.server.host)
228249

@@ -301,7 +322,6 @@ def test_features(self):
301322
@mark.slow
302323
@unittest.skipIf(platform.python_implementation() == "PyPy", "ftp unreliable with PyPy")
303324
class TestAnonFTPFS(FSTestCases, unittest.TestCase):
304-
305325
user = "anonymous"
306326
pasw = ""
307327

0 commit comments

Comments
 (0)