md5sum.py 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. #! /usr/bin/env python3
  2. """Python utility to print MD5 checksums of argument files.
  3. """
  4. bufsize = 8096
  5. fnfilter = None
  6. rmode = 'rb'
  7. usage = """
  8. usage: md5sum.py [-b] [-t] [-l] [-s bufsize] [file ...]
  9. -b : read files in binary mode (default)
  10. -t : read files in text mode (you almost certainly don't want this!)
  11. -l : print last pathname component only
  12. -s bufsize: read buffer size (default %d)
  13. file ... : files to sum; '-' or no files means stdin
  14. """ % bufsize
  15. import io
  16. import sys
  17. import os
  18. import getopt
  19. from hashlib import md5
  20. def sum(*files):
  21. sts = 0
  22. if files and isinstance(files[-1], io.IOBase):
  23. out, files = files[-1], files[:-1]
  24. else:
  25. out = sys.stdout
  26. if len(files) == 1 and not isinstance(files[0], str):
  27. files = files[0]
  28. for f in files:
  29. if isinstance(f, str):
  30. if f == '-':
  31. sts = printsumfp(sys.stdin, '<stdin>', out) or sts
  32. else:
  33. sts = printsum(f, out) or sts
  34. else:
  35. sts = sum(f, out) or sts
  36. return sts
  37. def printsum(filename, out=sys.stdout):
  38. try:
  39. fp = open(filename, rmode)
  40. except IOError as msg:
  41. sys.stderr.write('%s: Can\'t open: %s\n' % (filename, msg))
  42. return 1
  43. if fnfilter:
  44. filename = fnfilter(filename)
  45. sts = printsumfp(fp, filename, out)
  46. fp.close()
  47. return sts
  48. def printsumfp(fp, filename, out=sys.stdout):
  49. m = md5()
  50. try:
  51. while 1:
  52. data = fp.read(bufsize)
  53. if not data:
  54. break
  55. if isinstance(data, str):
  56. data = data.encode(fp.encoding)
  57. m.update(data)
  58. except IOError as msg:
  59. sys.stderr.write('%s: I/O error: %s\n' % (filename, msg))
  60. return 1
  61. out.write('%s %s\n' % (m.hexdigest(), filename))
  62. return 0
  63. def main(args = sys.argv[1:], out=sys.stdout):
  64. global fnfilter, rmode, bufsize
  65. try:
  66. opts, args = getopt.getopt(args, 'blts:')
  67. except getopt.error as msg:
  68. sys.stderr.write('%s: %s\n%s' % (sys.argv[0], msg, usage))
  69. return 2
  70. for o, a in opts:
  71. if o == '-l':
  72. fnfilter = os.path.basename
  73. elif o == '-b':
  74. rmode = 'rb'
  75. elif o == '-t':
  76. rmode = 'r'
  77. elif o == '-s':
  78. bufsize = int(a)
  79. if not args:
  80. args = ['-']
  81. return sum(args, out)
  82. if __name__ == '__main__' or __name__ == sys.argv[0]:
  83. sys.exit(main(sys.argv[1:], sys.stdout))