python-3.xftpftplibfile-processing

python ftplib ftp.rename() throwing error in some servers


Just started working on some python scripts with FTP and SFTP. SFTP seems to work fine in all scenarios, but when the script tries to rename a file using FTP, it works on some servers and it throws errors in some. I am currently working on python 3.9.6 and sharing the code sample below.

ftp = FTP(host='ip', user='user', passwd='password')

if ftp.size("/path/to/some/directory/filename.txt") is not None:
  print("{} is a file".format("/path/to/some/directory/filename.txt"))
else:
  print("It's NOT a file!")

try:
  print("Downloading file")
  with open("/path/to/some/directory/filename.txt", "wb") as file:
      ftp.retrbinary("RETR %s" %file_path + file_name, file.write)
      file.close()

  print("Download completed!")

  try:
      ftp.rename(fromname="/path/to/some/directory/filename.txt", toname="/path/to/backup/filename" + "_" + str(datetime.datetime.now()).replace(" ", "_") + ".txt")
                      
      print("File renamed.")
  except:
      traceback.print_exc()

except:
  print("Excetion while Downloading file!")
  traceback.print_exc()

ftp.quit()

I've tested this code on 3 different servers. On the first 2, I'm getting success (which is, the file is moved correctly). For the last one, I'm getting the following error

Traceback (most recent call last):
  File "/path/to/script/ftp.py", line 37, in <module>
    ftp.rename(fromname="/path/to/some/directory/filename.txt", toname="/path/to/backup/filename" + "_" + str(datetime.datetime.now()).replace(" ", "_") + ".txt")
  File "/usr/local/lib/python3.9/ftplib.py", line 604, in rename
    return self.voidcmd('RNTO ' + toname)
  File "/usr/local/lib/python3.9/ftplib.py", line 286, in voidcmd
    return self.voidresp()
  File "/usr/local/lib/python3.9/ftplib.py", line 259, in voidresp
    resp = self.getresp()
  File "/usr/local/lib/python3.9/ftplib.py", line 252, in getresp
    raise error_temp(resp)
ftplib.error_temp: 450 Internal error renaming the file

This is happening only in the last server I tried the script. One more thing I noticed is that rename command works when I log in as an FTP user to that server and try to rename the file manually. This means that the FTP user has the privilege for both the file and backup path.

Adding the debuglevel(2) logs of both error and success cases. Note: These logs are from 2 different servers with the same script. And to identify the issue, I've used only the renaming code in the script.

Logs from the server where the script runs successfully on - vsFTPd 3.0.2

Renaming file
cmd 'RNFR /path/to/some/directory/filename.txt'
put 'RNFR /path/to/some/directory/filename.txt\r\n'
get '350 Ready for RNTO.\n'
resp '350 Ready for RNTO.'
cmd 'RNTO /path/to/backup/filename_2022-06-01_10:31:45.765201.txt'
put 'RNTO /path/to/backup/filename_2022-06-01_10:31:45.765201.txt\r\n'
get '250 Rename successful.\n'
resp '250 Rename successful.'
File renamed.

Logs from the server where the script fails on - FileZilla Server 0.9.60 beta

Renaming file
cmd 'RNFR /path/to/some/directory/sample_tst.txt'
put 'RNFR /path/to/some/directory/sample_tst.txt\r\n'
get '350 File exists, ready for destination name.\n'
resp '350 File exists, ready for destination name.'
cmd 'RNTO /path/to/backup/filename_2022-06-01_10:16:45.088433.txt'
put 'RNTO /path/to/backup/filename_2022-06-01_10:16:45.088433.txt\r\n'
get '450 Internal error renaming the file\n'
resp '450 Internal error renaming the file'
Excetion while renaming file: <class 'ftplib.error_temp'>
Traceback (most recent call last):
  File "/opt/APPS/SCRIPT/ftp.py", line 36, in <module>
    ftp.rename(fromname="/path/to/some/directory/filename.txt", toname="/path/to/backup/filename" + "_" + str(datetime.datetime.now()).replace(" ", "_") + ".txt")
  File "/usr/local/lib/python3.9/ftplib.py", line 604, in rename
    return self.voidcmd('RNTO ' + toname)
  File "/usr/local/lib/python3.9/ftplib.py", line 286, in voidcmd
    return self.voidresp()
  File "/usr/local/lib/python3.9/ftplib.py", line 259, in voidresp
    resp = self.getresp()
  File "/usr/local/lib/python3.9/ftplib.py", line 252, in getresp
    raise error_temp(resp)
ftplib.error_temp: 450 Internal error renaming the file

Here is the debug level log when I tried to do it manually in the failure server.

ftp> debug 2
Debugging on (debug=2).
ftp> 
ftp> 
ftp> rename /path/to/some/directory/filename.txt /path/to/backup/filename_2022-06-01_12:16.txt
---> RNFR /path/to/some/directory/filename.txt
350 File exists, ready for destination name.
---> RNTO /path/to/backup/filename_2022-06-01_12:16.txt
250 file renamed successfully
ftp> 

Above is a screenshot for which I've tried to move it using rename command when I logged in as FTP user.

I've been researching about this for the past couple of days and getting nowhere. I would be grateful if someone could help me with this issue.

Both the servers run on Red Hat Enterprise Linux

Thanks in advance.


Solution

  • The issue was with the filename. Full colons were not supported. So instead appending the full timestamp, I've formatted it as below.

    ftp.rename(fromname="/path/to/some/directory/filename.txt", toname="/path/to/backup/filename" + "_" + str(datetime.datetime.now().strftime("%Y-%m-%d %H%M%S")).replace(" ", "_") + ".txt")
    

    And it's working now. Thanks, @Martin for pointing out the mistake.