4

Once transferring a file to a server using ftplib, how do I determine the MD5 of that file to the one in my local server?

from ftplib import FTP
import hashlib

ftp = FTP('server')
ftp.login('username','password')
ftp.cwd('path_to_upload')

file_to_upload = open(file,'rb') 
filename = os.path.basename(file)
ftp.storbinary('STOR ' + filename, file_to_upload)

local_file_hash = hashlib.md5(open(file, 'rb').read()).hexdigest()
# not sure how to achieve this
server_file_hash = hashlib.md5(open(filename, 'rb').read()).hexdigest() 

if local_file_hash == server_file_hash:
     print("Successful transfer")
else:
     print("Failure transfer")
Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992

2 Answers2

2

First, make sure your remote server supports the checksum calculation at all. Many do not. I believe there's even no standard FTP command to calculate a checksum of a remote file. There were many proposals and there are many proprietary solutions.

The latest proposal is:
https://datatracker.ietf.org/doc/html/draft-bryan-ftpext-hash-02

Some of the commands that can be used to calculate checksum are: XSHA1, XSHA256, XSHA512, XMD5, MD5, XCRC and HASH.

You can test that with WinSCP FTP client. The WinSCP supports all the previously mentioned commands. Test its checksum calculation function or the checksum scripting command. If they work, enable logging and check, what command and what syntax WinSCP uses against your server. (I'm the author of WinSCP)

Once you find out, what command does your server support (if any), you can use FTP.voidcmd method:

ftp.voidcmd("XSHA1 " + filename)
Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
-1

I encountered a similar issue and came across the following solution, which would work regardless of whether server commands are possible

Source: https://smithje.github.io/python/2013/07/02/md5-over-ftp

In short, one could use the .retrbinary and load it into Hash object:

import ftplib
import hashlib

def get_ftp_md5(ftp, remote_path):
    m = hashlib.md5()
    ftp.retrbinary(f'RETR {remote_path}', m.update)
    return m.hexdigest()
astrochun
  • 1,642
  • 2
  • 7
  • 18
  • 1
    This way you are downloading a complete file back to the local machine. Then it makes little sense to compare the checksums (let only weak one like MD5), as you can compare complete file contents. – Martin Prikryl Aug 11 '22 at 06:53
  • @MartinPrikryl, Yes it's downloading the file, but as you stated, not all FTPS server allow for HASH commands, so this is a workaround for the same approach. – astrochun Aug 24 '22 at 15:45