diff --git a/Changelog b/Changelog index 63f86dc..db3ab63 100644 --- a/Changelog +++ b/Changelog @@ -1,6 +1,7 @@ 2025-xx-xx - v3.2.1.dev0: * WARNING: This is a development snapshot, not a stable release. * Support for BLAKE3 b3sum format (Thanks to Artur Ladka). + * Support for BLAKE2 b2sum format (Thanks to Artur Ladka). 2025-11-02 - v3.2.0: * Drop support for Python 3.6. diff --git a/README.md b/README.md index 78c5b23..dc60c09 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ cfv is a utility to test and create a wide range of checksum verification files. It currently supports testing and creating sfv, sfvmd5, csv, csv2, csv4, crc, md5, bsdmd5, -sha1, sha224, sha256, sha384, sha512, b3 (BLAKE3) and torrent files. +sha1, sha224, sha256, sha384, sha512, b2 (BLAKE2b), b3 (BLAKE3) and torrent files. Test-only support is available for par, par2. cfv was originally written by Matthew Mueller ([original project home](http://cfv.sourceforge.net/)). diff --git a/cfv.1 b/cfv.1 index 181100f..cb27fc7 100644 --- a/cfv.1 +++ b/cfv.1 @@ -1,6 +1,6 @@ .TH cfv 1 "05 Feb 2005" .SH NAME -cfv \- Verify file consistency with .sfv, .csv, .crc, .md5, md5sum, sha1sum, sha224sum, sha256sum, sha384sum, sha512sum, b3sum, .torrent, .par, or .par2 files +cfv \- Verify file consistency with .sfv, .csv, .crc, .md5, md5sum, sha1sum, sha224sum, sha256sum, sha384sum, sha512sum, b2sum, b3sum, .torrent, .par, or .par2 files .SH SYNOPSIS .B cfv [\-p dir] [\-v|\-V|\-VV|\-q|\-Q] [\-\-progress VAL] [\-r|\-rr|\-R] [\-l|\-L] [\-n|\-N] [\-\-renameformat ] [\-s|\-S] [\-zz|\-z|\-Z|\-ZZ] [\-T|\-C] [\-m|\-M] [\-i|\-I] [\-u|\-uu|\-U] [\-\-encoding ] [\-\-unquote ] [\-\-fixpaths ] [\-\-strippaths

] [\-\-showpaths ] [\-\-list/\-\-list0 ] [\-\-announceurl ] [\-\-piece_size_pow2 ] [\-\-private_torrent] [\-\-length ] [\-t type] [\-f file] [files...] .SH DESCRIPTION @@ -120,7 +120,7 @@ Specify the name of the checksum file to test or create. If file is \-, stdin (for \-T) or stdout (for \-C) will be used. .IP "\-t type" Specify the type of the file. -Can be sfv, sfvmd5, csv, csv2, csv4, crc, md5, bsdmd5, sha1, sha224, sha256, sha384, sha512, b3, torrent, par, par2, auto, or help. +Can be sfv, sfvmd5, csv, csv2, csv4, crc, md5, bsdmd5, sha1, sha224, sha256, sha384, sha512, b2, b3, torrent, par, par2, auto, or help. For details see supported checksum formats section. If the type is help, or an unknown type is given, a list of the types and their descriptions will be printed. The default is auto, which will detect the file type for you. @@ -130,8 +130,9 @@ Prints a raw listing of files in the given set (ok, bad, unverified, notfound). .IP "\-\-list0 listset" Like \-\-list but files are separated by a null char. Useful in combination with xargs \-0. .IP "\-\-length BITS" -Set digest length in bits for hash types that support variable output (b3). -The default for b3 is 256 bits. Must be a multiple of 8. +Set digest length in bits for hash types that support variable output (b2, b3). +The default is 512 bits for b2 and 256 bits for b3. Must be a multiple of 8. +For b2 the maximum is 512 bits. .IP "\-\-announceurl URL" Tracker announce URL for .torrent file creation. .IP "\-\-piece_size_pow2 N" @@ -185,6 +186,9 @@ is a GNU sha384sum format file .B sha512 is a GNU sha512sum format file .br +.B b2 +is a BLAKE2b b2sum format file (B2SUMS, .b2, .blk). Default digest size is 512 bits. +.br .B b3 is a BLAKE3 b3sum format file (B3SUMS, .b3, .bk3). Requires the Python blake3 module. .br diff --git a/lib/cfv/common.py b/lib/cfv/common.py index 48a33d9..73a1e70 100644 --- a/lib/cfv/common.py +++ b/lib/cfv/common.py @@ -785,47 +785,35 @@ def make_addfile(self, filename): pass -# ---------- b3 (BLAKE3) ---------- +# ---------- HashSum base (shared by b2/b3) ---------- + +# Match any even-length hex string (supports variable digest lengths when checking) +_hashsum_rem = re.compile(r'((?:[0-9a-fA-F]{2})+) [ *]([^\r\n]+)[\r\n]*$') -class BLAKE3_MixIn(object): - digest_size = 32 - hash_name = 'blake3' + +class HashSumBase(TextChksumType): + """Shared base for coreutils-style hash checksum formats (b2sum, b3sum).""" + auto_chksumfile_order = 1 + digest_size = None # default digest size in bytes, set by subclass + max_digest_size = None # max allowed digest size in bytes (None = unlimited) + hash_name = None # e.g. 'blake2b', 'blake3' + _hash_func = None # e.g. hash.getfileblake2b, hash.getfileblake3 + _std_ext = None # e.g. '.b2', '.b3' def do_test_file(self, filename, filecrc): # Derive digest size from the checksum in the file (supports variable lengths) digest_size = len(filecrc) - - c = getfilehash(filename, '%s-%d' % (self.hash_name, digest_size), hash.getfileblake3, digest_size)[0] + c = getfilehash(filename, '%s-%d' % (self.hash_name, digest_size), self._hash_func, digest_size)[0] if c != filecrc: return c - -class BLAKE3(TextChksumType, BLAKE3_MixIn): - name = 'b3' - description = 'BLAKE3 b3sum' - descinfo = 'BLAKE3,name' - auto_chksumfile_order = 1 - auto_filename_match = r'b3sum|\.(b3|bk3)$' - - # Match any even-length hex string (supports variable digest lengths when checking) - _b3rem = re.compile(r'((?:[0-9a-fA-F]{2})+) [ *]([^\r\n]+)[\r\n]*$') - def do_test_chksumfile_print_testingline(self, file): comment = parse_commentline(file.peekline(512).lstrip(), ';') TextChksumType.do_test_chksumfile_print_testingline(self, file, comment) - @staticmethod - def _is_b3_filename(filename): - if not filename: - return False - lname = filename.lower() - if lname.endswith('.gz'): - lname = lname[:-3] - return lname.endswith('.b3') or lname.endswith('.bk3') or 'b3sum' in os.path.basename(lname) - @classmethod def auto_chksumfile_match(cls, file): - if not cls._is_b3_filename(file.name): + if not cls._is_valid_filename(file.name): return False line = file.peekline(4096) while line: @@ -833,30 +821,83 @@ def auto_chksumfile_match(cls, file): if not stripped or stripped.startswith(';'): line = file.peeknextline(4096) continue - return cls._b3rem.match(stripped) is not None + return _hashsum_rem.match(stripped) is not None return False def do_test_chksumline(self, line): stripped = line.lstrip() if not stripped or stripped.startswith(';'): return - x = self._b3rem.match(stripped) + x = _hashsum_rem.match(stripped) if not x: return -1 + digest_size = len(x.group(1)) // 2 + if self.max_digest_size and digest_size > self.max_digest_size: + return -1 self.test_file(x.group(2), strutil.unhexlify(x.group(1))) - @staticmethod - def make_std_filename(filename): - return filename + '.b3' + @classmethod + def make_std_filename(cls, filename): + return filename + cls._std_ext def make_addfile(self, filename): digest_size = config.hash_length // 8 if config.hash_length else self.digest_size + if self.max_digest_size and digest_size > self.max_digest_size: + raise CFVValueError('--length for %s must be between 8 and %d' % (self.name, self.max_digest_size * 8)) cache_key = '%s-%d' % (self.hash_name, digest_size) - digest = getfilehash(filename, cache_key, hash.getfileblake3, digest_size)[0] + digest = getfilehash(filename, cache_key, self._hash_func, digest_size)[0] hexdigest = strutil.hexlify(digest) return (hexdigest, -1), '%s %s' % (hexdigest, filename) + os.linesep +# ---------- b2 (BLAKE2) ---------- + +class BLAKE2(HashSumBase): + name = 'b2' + description = 'BLAKE2b b2sum' + descinfo = 'BLAKE2b,name' + digest_size = 64 + max_digest_size = 64 + hash_name = 'blake2b' + _hash_func = staticmethod(hash.getfileblake2b) + _std_ext = '.b2' + auto_filename_match = r'b2sum|\.(b2|blk)$' + + @staticmethod + def _is_valid_filename(filename): + if not filename: + return False + lname = filename.lower() + if lname.endswith('.gz'): + lname = lname[:-3] + return lname.endswith('.b2') or lname.endswith('.blk') or 'b2sum' in os.path.basename(lname) + + +cftypes.register_cftype(BLAKE2) + + +# ---------- b3 (BLAKE3) ---------- + +class BLAKE3(HashSumBase): + name = 'b3' + description = 'BLAKE3 b3sum' + descinfo = 'BLAKE3,name' + digest_size = 32 + hash_name = 'blake3' + _hash_func = staticmethod(hash.getfileblake3) + _std_ext = '.b3' + auto_filename_match = r'b3sum|\.(b3|bk3)$' + + @staticmethod + def _is_valid_filename(filename): + if not filename: + return False + lname = filename.lower() + if lname.endswith('.gz'): + lname = lname[:-3] + return lname.endswith('.b3') or lname.endswith('.bk3') or 'b3sum' in os.path.basename(lname) + + cftypes.register_cftype(BLAKE3) @@ -1797,6 +1838,10 @@ def make(cftype, ifilename, testfiles): view.ev_make_cf_typenotsupported(filename, cftype) stats.cferror += 1 return + max_digest_size = getattr(cftype, 'max_digest_size', None) + if max_digest_size and config.hash_length and config.hash_length // 8 > max_digest_size: + view.perror('cfv: --length for %s must be between 8 and %d' % (cftype.name, max_digest_size * 8)) + sys.exit(1) if os.path.exists(filename): view.ev_make_cf_alreadyexists(filename) stats.cferror += 1 @@ -2005,7 +2050,7 @@ def show_unverified_files(filelist): # md5sum/sha1sum files have no standard extension, so just search for # files with md5/sha1 in the name anywhere, and let the test func see # if it really is one. -atrem = re.compile(r'md5|sha1|sha224|sha256|sha384|sha512|b3sum|\.(b3|bk3|csv|sfv|par|p[0-9][0-9]|par2|torrent|crc)(\.gz)?$', re.IGNORECASE) +atrem = re.compile(r'md5|sha1|sha224|sha256|sha384|sha512|b2sum|b3sum|\.(b2|blk|b3|bk3|csv|sfv|par|p[0-9][0-9]|par2|torrent|crc)(\.gz)?$', re.IGNORECASE) def autotest(typename): @@ -2071,8 +2116,8 @@ def printusage(err=0): phelp(' --progress=VAL show progress meter (yes, no, or auto(default))') phelp(' --help/-h show help') phelp(' --version show cfv and module versions') - phelp('creation options (b3):') - phelp(' --length=BITS digest length in bits (default: 256 for b3)') + phelp('creation options (b2, b3):') + phelp(' --length=BITS digest length in bits (default: 512 for b2, 256 for b3)') phelp('creation options (torrent):') phelp(' --announceurl=URL tracker announce url') phelp(' --piece_size_pow2=N power of two to set the piece size to (default 18)') diff --git a/lib/cfv/hash.py b/lib/cfv/hash.py index b3c5cca..3d11008 100644 --- a/lib/cfv/hash.py +++ b/lib/cfv/hash.py @@ -126,3 +126,9 @@ def getfileblake3(filename, callback, digest_size): callback, finalize=lambda h: h.digest(digest_size), ) + + +def getfileblake2b(filename, callback, digest_size): + def hasher(data=b''): + return hashlib.blake2b(data, digest_size=digest_size) + return _getfilechecksum(filename, hasher, callback) diff --git a/test/test.py b/test/test.py index 7bd5423..1307795 100755 --- a/test/test.py +++ b/test/test.py @@ -104,6 +104,8 @@ def is_encodable(s, enc=preferredencoding): (1, 1, 0, 1, 0, preferredencoding, 0), 'torrent': (1, 1, 1, 1, 0, 'utf-8', 0), + 'b2': + (1, 0, 1, 1, 1, preferredencoding, 0), 'b3': (1, 0, 1, blake3_available, 1, preferredencoding, 0), } @@ -635,14 +637,17 @@ def missing_dep_test(s, o): shutil.rmtree(stubdir) -def b3_roundtrip_test(): +def _hashsum_roundtrip_test(typename, digest_bytes): + """Test create + verify cycle for a hashsum type.""" tmpd = tempfile.mkdtemp() try: input_name = 'input.txt' input_path = os.path.join(tmpd, input_name) with open(input_path, 'wt') as f: f.write('hello\n') - cfpath = os.path.join(tmpd, 'out.b3') + cfpath = os.path.join(tmpd, 'out.%s' % typename) + + hex_chars = digest_bytes * 2 def create_test(s, o): if s != 0: @@ -651,51 +656,43 @@ def create_test(s, o): if line and not line.lstrip().startswith(';')] if len(lines) != 1: return 'expected 1 data line, got %d' % len(lines) - pattern = r'^[0-9a-f]{64} %s$' % re.escape(input_name) + pattern = r'^[0-9a-f]{%d} %s$' % (hex_chars, re.escape(input_name)) if not re.match(pattern, lines[0]): - return 'bad b3 line: %r' % lines[0] + return 'bad %s line: %r' % (typename, lines[0]) return 0 - test_generic('%s -C -t b3 -p %s -f out.b3 %s' % (cfvcmd, tmpd, input_name), create_test) - test_generic('%s -T -p %s -f out.b3' % (cfvcmd, tmpd), cfv_test) + test_generic('%s -C -t %s -p %s -f out.%s %s' % (cfvcmd, typename, tmpd, typename, input_name), create_test) + test_generic('%s -T -p %s -f out.%s' % (cfvcmd, tmpd, typename), cfv_test) finally: shutil.rmtree(tmpd) -def b3_fixture_test(): - """Test that .b3 and legacy .bk3 files with various hash lengths are all verified correctly.""" - fixtures = ( - 'test.b3', - 'test.bk3', - 'B3SUMS', - 'test.blake3-512.b3', - 'test.blake3-1024.b3', - 'test.blake3-2048.b3', - ) +def _hashsum_fixture_test(fixtures): + """Test that fixture files are all verified correctly.""" for fixture in fixtures: test_generic('%s -T -f %s' % (cfvcmd, fixture), cfv_test) -def b3_b3sums_create_test(): - """Test that -C -f B3SUMS auto-detects as b3 type.""" +def _hashsum_auto_filename_create_test(auto_filename, typename): + """Test that -C -f auto-detects as the correct type.""" tmpd = tempfile.mkdtemp() try: input_name = 'input.txt' input_path = os.path.join(tmpd, input_name) with open(input_path, 'wt') as f: f.write('hello\n') - test_generic('%s -C -p %s -f B3SUMS %s' % (cfvcmd, tmpd, input_name), cfv_test) - test_generic('%s -T -p %s -f B3SUMS' % (cfvcmd, tmpd), cfv_test) + test_generic('%s -C -p %s -f %s %s' % (cfvcmd, tmpd, auto_filename, input_name), cfv_test) + test_generic('%s -T -p %s -f %s' % (cfvcmd, tmpd, auto_filename), cfv_test) finally: shutil.rmtree(tmpd) -def b3_malformed_hex_test(): - """Test that odd-length hex in .b3 file is rejected gracefully, not a traceback.""" +def _hashsum_malformed_hex_test(typename): + """Test that odd-length hex is rejected gracefully, not a traceback.""" tmpd = tempfile.mkdtemp() try: - bad_b3 = os.path.join(tmpd, 'bad.b3') - with open(bad_b3, 'wt') as f: + bad_file = os.path.join(tmpd, 'bad.%s' % typename) + with open(bad_file, 'wt') as f: f.write('abc data1\n') def malformed_test(s, o): @@ -703,12 +700,12 @@ def malformed_test(s, o): return 'expected exit code 64 (cferror), got %d' % s return 0 - test_generic('%s -T -f %s' % (cfvcmd, bad_b3), malformed_test) + test_generic('%s -T -f %s' % (cfvcmd, bad_file), malformed_test) finally: shutil.rmtree(tmpd) -def b3_length_test(): +def _hashsum_length_test(typename, length_bits): """Test --length option for variable digest size (in bits).""" tmpd = tempfile.mkdtemp() try: @@ -716,7 +713,9 @@ def b3_length_test(): input_path = os.path.join(tmpd, input_name) with open(input_path, 'wt') as f: f.write('hello\n') - cfpath = os.path.join(tmpd, 'out.b3') + cfpath = os.path.join(tmpd, 'out.%s' % typename) + + hex_chars = length_bits // 4 def create_test(s, o): if s != 0: @@ -725,22 +724,42 @@ def create_test(s, o): if line and not line.lstrip().startswith(';')] if len(lines) != 1: return 'expected 1 data line, got %d' % len(lines) - # 512 bits = 64 bytes = 128 hex chars - pattern = r'^[0-9a-f]{128} %s$' % re.escape(input_name) + pattern = r'^[0-9a-f]{%d} %s$' % (hex_chars, re.escape(input_name)) if not re.match(pattern, lines[0]): - return 'bad b3 --length=512 line: %r' % lines[0] + return 'bad %s --length=%d line: %r' % (typename, length_bits, lines[0]) + return 0 + + test_generic('%s -C -t %s --length=%d -p %s -f out.%s %s' % (cfvcmd, typename, length_bits, tmpd, typename, input_name), create_test) + test_generic('%s -T -p %s -f out.%s' % (cfvcmd, tmpd, typename), cfv_test) + finally: + shutil.rmtree(tmpd) + + +def _hashsum_invalid_length_test(typename, invalid_length): + """Test that --length with invalid value (in bits) produces a clean error.""" + tmpd = tempfile.mkdtemp() + try: + input_name = 'input.txt' + input_path = os.path.join(tmpd, input_name) + with open(input_path, 'wt') as f: + f.write('hello\n') + + def invalid_length_test(s, o): + if s != 1: + return 'expected exit code 1, got %d' % s + if '--length' not in o or 'must be between' not in o: + return 'unexpected error output: %r' % o return 0 - test_generic('%s -C -t b3 --length=512 -p %s -f out.b3 %s' % (cfvcmd, tmpd, input_name), create_test) - test_generic('%s -T -p %s -f out.b3' % (cfvcmd, tmpd), cfv_test) + test_generic('%s -C -t %s --length=%d -p %s -f out.%s %s' % (cfvcmd, typename, invalid_length, tmpd, typename, input_name), invalid_length_test) finally: shutil.rmtree(tmpd) -def b3sum_compat_test(): - """Test interoperability with b3sum tool (requires b3sum to be installed).""" - if not pathfind('b3sum'): - print('skipping b3sum compatibility tests, b3sum not installed.') +def _hashsum_tool_compat_test(typename, toolname): + """Test interoperability with external tool (requires tool to be installed).""" + if not pathfind(toolname): + print('skipping %s compatibility tests, %s not installed.' % (typename, toolname)) return tmpd = tempfile.mkdtemp() @@ -749,22 +768,22 @@ def b3sum_compat_test(): for fname in test_files: shutil.copy(fname, os.path.join(tmpd, fname)) - # Test 1: b3sum -> cfv - cmd = 'cd %s && b3sum %s > b3sum_out.b3' % (tmpd, ' '.join(test_files)) - test_external(cmd, lambda s, _: 0 if s == 0 else 'b3sum create failed') - test_generic('%s -T -p %s -f b3sum_out.b3' % (cfvcmd, tmpd), cfv_test) + # Test 1: tool -> cfv + cmd = 'cd %s && %s %s > %s_out.%s' % (tmpd, toolname, ' '.join(test_files), toolname, typename) + test_external(cmd, lambda s, _: 0 if s == 0 else '%s create failed' % toolname) + test_generic('%s -T -p %s -f %s_out.%s' % (cfvcmd, tmpd, toolname, typename), cfv_test) - # Test 2: cfv -> b3sum - test_generic('%s -C -t b3 -p %s -f cfv_out.b3 %s' % ( - cfvcmd, tmpd, ' '.join(test_files)), cfv_test) + # Test 2: cfv -> tool + test_generic('%s -C -t %s -p %s -f cfv_out.%s %s' % ( + cfvcmd, typename, tmpd, typename, ' '.join(test_files)), cfv_test) - cmd = 'cd %s && b3sum -c cfv_out.b3' % tmpd + cmd = 'cd %s && %s -c cfv_out.%s' % (tmpd, toolname, typename) - def b3sum_verify(s, o): + def tool_verify(s, o): if s != 0: - return 'b3sum verify failed: %s' % o + return '%s verify failed: %s' % (toolname, o) return 0 - test_external(cmd, b3sum_verify) + test_external(cmd, tool_verify) finally: shutil.rmtree(tmpd) @@ -1822,14 +1841,22 @@ def all_tests(): deep_unverified_test() hash_length_non_byte_aligned_test() + _hashsum_roundtrip_test('b2', 64) + _hashsum_length_test('b2', 256) + _hashsum_invalid_length_test('b2', 520) + _hashsum_fixture_test(('test.b2', 'test.blk', 'B2SUMS', 'test.blake2b-256.b2', 'test.blake2b-384.b2')) + _hashsum_auto_filename_create_test('B2SUMS', 'b2') + _hashsum_malformed_hex_test('b2') + _hashsum_tool_compat_test('b2', 'b2sum') + blake3_missing_dep_test() if blake3_available: - b3_roundtrip_test() - b3_length_test() - b3_fixture_test() - b3_b3sums_create_test() - b3_malformed_hex_test() - b3sum_compat_test() + _hashsum_roundtrip_test('b3', 32) + _hashsum_length_test('b3', 512) + _hashsum_fixture_test(('test.b3', 'test.bk3', 'B3SUMS', 'test.blake3-512.b3', 'test.blake3-1024.b3', 'test.blake3-2048.b3')) + _hashsum_auto_filename_create_test('B3SUMS', 'b3') + _hashsum_malformed_hex_test('b3') + _hashsum_tool_compat_test('b3', 'b3sum') else: print('skipping b3 tests, blake3 not installed.') @@ -1844,6 +1871,7 @@ def all_tests(): ren_test('csv4') ren_test('crc') ren_test('torrent') + ren_test('b2') if blake3_available: ren_test('b3') @@ -1877,6 +1905,7 @@ def all_tests(): T_test('nosize.crc') T_test('nodims.crc') T_test('nosizenodimsnodesc.crc') + T_test('.b2') if blake3_available: T_test('.b3') for fmt in coreutilsfmts(): @@ -1888,6 +1917,7 @@ def all_tests(): T_test('crlf.sfv') T_test('noheadercrlf.sfv') T_test('crlf.crc') + T_test('crlf.b2') if blake3_available: T_test('crlf.b3') for fmt in coreutilsfmts(): @@ -1899,6 +1929,7 @@ def all_tests(): T_test('crcrlf.sfv') T_test('noheadercrcrlf.sfv') T_test('crcrlf.crc') + T_test('crcrlf.b2') if blake3_available: T_test('crcrlf.b3') for strip in (0, 1): @@ -1980,6 +2011,13 @@ def sfvverify(f): C_test('csv2', '-t csv2') C_test('csv4', '-t csv4') C_test('crc') + if pathfind('b2sum'): + def b2sum_verify(f): + test_external('b2sum -c ' + f, status_test) + else: + print('skipping b2 verify using external tool b2sum, as it is not installed.') + b2sum_verify = None + C_test('b2', '-t b2', verify=b2sum_verify) if blake3_available: if pathfind('b3sum'): # don't report pointless errors on systems that don't have b3sum def b3sum_verify(f): @@ -2033,6 +2071,7 @@ def b3sum_verify(f): test_generic(cfvcmd + ' -m -v -T -t csv', lambda s, o: cfv_typerestrict_test(s, o, 'csv')) test_generic(cfvcmd + ' -m -v -T -t par', lambda s, o: cfv_typerestrict_test(s, o, 'par')) test_generic(cfvcmd + ' -m -v -T -t par2', lambda s, o: cfv_typerestrict_test(s, o, 'par2')) + test_generic(cfvcmd + ' -m -v -T -t b2', lambda s, o: cfv_typerestrict_test(s, o, 'b2')) test_generic(cfvcmd + ' -m -v -T -t b3', lambda s, o: cfv_typerestrict_test(s, o, 'b3')) test_generic(cfvcmd + ' -u -t md5 -f test.md5 data* unchecked.dat test.md5', cfv_unv_test) diff --git a/test/testdata/B2SUMS b/test/testdata/B2SUMS new file mode 100644 index 0000000..adc65c7 --- /dev/null +++ b/test/testdata/B2SUMS @@ -0,0 +1,4 @@ +5c5ce11923c07698f54cf30196efb3b038b44a77046fbabbdf3f2c2a924e10081e5f79cb4cd562f5590dc917c67fc0cdfaec0a992469e5cd0b3f7d1c249f9015 data1 +5c5ce11923c07698f54cf30196efb3b038b44a77046fbabbdf3f2c2a924e10081e5f79cb4cd562f5590dc917c67fc0cdfaec0a992469e5cd0b3f7d1c249f9015 data2 +8430fa32c8686a0d6a62769affdf454fc8429eacfbaf1eced94d95ecc1efef938616501103e58e7bd2371553c60e12ac274eac537efd0fbd6171f73536bc9a61 data3 +c5d36b0ab741961fcfd8fc4250cb642905a5c5bb3649f5ace664a1b0bd57efd77626e8a7252c1499c71a05c54a0cf548acbc051c2a89cd490a242cd4963e7885 data4 diff --git a/test/testdata/test.b2 b/test/testdata/test.b2 new file mode 100644 index 0000000..adc65c7 --- /dev/null +++ b/test/testdata/test.b2 @@ -0,0 +1,4 @@ +5c5ce11923c07698f54cf30196efb3b038b44a77046fbabbdf3f2c2a924e10081e5f79cb4cd562f5590dc917c67fc0cdfaec0a992469e5cd0b3f7d1c249f9015 data1 +5c5ce11923c07698f54cf30196efb3b038b44a77046fbabbdf3f2c2a924e10081e5f79cb4cd562f5590dc917c67fc0cdfaec0a992469e5cd0b3f7d1c249f9015 data2 +8430fa32c8686a0d6a62769affdf454fc8429eacfbaf1eced94d95ecc1efef938616501103e58e7bd2371553c60e12ac274eac537efd0fbd6171f73536bc9a61 data3 +c5d36b0ab741961fcfd8fc4250cb642905a5c5bb3649f5ace664a1b0bd57efd77626e8a7252c1499c71a05c54a0cf548acbc051c2a89cd490a242cd4963e7885 data4 diff --git a/test/testdata/test.blake2b-256.b2 b/test/testdata/test.blake2b-256.b2 new file mode 100644 index 0000000..3c2c016 --- /dev/null +++ b/test/testdata/test.blake2b-256.b2 @@ -0,0 +1,4 @@ +ca57d5b2364b0e3660f8dd44eafed7455b7ba59e3652309b45475edd9aaa1eeb data1 +ca57d5b2364b0e3660f8dd44eafed7455b7ba59e3652309b45475edd9aaa1eeb data2 +c33afdab7677b3bdd620899b1f60ef432a408a371b8481a33f9772f4e3d77331 data3 +5044688a6ab7dca48e0d4e3cea00593351f78014f01a75f5febe8ad64b823cc8 data4 diff --git a/test/testdata/test.blake2b-384.b2 b/test/testdata/test.blake2b-384.b2 new file mode 100644 index 0000000..1e10e46 --- /dev/null +++ b/test/testdata/test.blake2b-384.b2 @@ -0,0 +1,4 @@ +f9d117faeecc9a581ad7f8cf82b9d0e0dad0c5526659de49c86222fc0a5f288ae7ecba1330266b6fbb71b26efe0511ca *data1 +f9d117faeecc9a581ad7f8cf82b9d0e0dad0c5526659de49c86222fc0a5f288ae7ecba1330266b6fbb71b26efe0511ca *data2 +61bc57266ec9597383cdb7839750c0b15f3a8d6745635f143705940e0c32981302f154634d2069d2ae7e1055ab1cb86c *data3 +3b93539096e33b1ae49499788cd575fd6eb24c0c46141fb6c140b098d45e3de5ad9509a5062a09cb5c8fa6a259859011 *data4 diff --git a/test/testdata/test.blk b/test/testdata/test.blk new file mode 100644 index 0000000..dfba965 --- /dev/null +++ b/test/testdata/test.blk @@ -0,0 +1,15 @@ +; Generated by TurboSFV (v10.61.10061) on 2026-01-25 09:40:52 +; https://www.turbosfv.com/ +; Hash type : BLAKE2B-512 +; Files total : 4 +; Bytes total : 1,391 +; ------------------------------------------------ +; Files hashed : 4 +; 2026-01-24 14:01:07 13 data1 +; 2026-01-24 14:01:07 13 data2 +; 2026-01-24 14:01:07 13 data3 +; 2026-01-24 14:01:07 1,352 data4 +5c5ce11923c07698f54cf30196efb3b038b44a77046fbabbdf3f2c2a924e10081e5f79cb4cd562f5590dc917c67fc0cdfaec0a992469e5cd0b3f7d1c249f9015 *data1 +5c5ce11923c07698f54cf30196efb3b038b44a77046fbabbdf3f2c2a924e10081e5f79cb4cd562f5590dc917c67fc0cdfaec0a992469e5cd0b3f7d1c249f9015 *data2 +8430fa32c8686a0d6a62769affdf454fc8429eacfbaf1eced94d95ecc1efef938616501103e58e7bd2371553c60e12ac274eac537efd0fbd6171f73536bc9a61 *data3 +c5d36b0ab741961fcfd8fc4250cb642905a5c5bb3649f5ace664a1b0bd57efd77626e8a7252c1499c71a05c54a0cf548acbc051c2a89cd490a242cd4963e7885 *data4 diff --git a/test/testdata/testcrcrlf.b2 b/test/testdata/testcrcrlf.b2 new file mode 100644 index 0000000..640600c --- /dev/null +++ b/test/testdata/testcrcrlf.b2 @@ -0,0 +1,4 @@ +5c5ce11923c07698f54cf30196efb3b038b44a77046fbabbdf3f2c2a924e10081e5f79cb4cd562f5590dc917c67fc0cdfaec0a992469e5cd0b3f7d1c249f9015 *data1 +5c5ce11923c07698f54cf30196efb3b038b44a77046fbabbdf3f2c2a924e10081e5f79cb4cd562f5590dc917c67fc0cdfaec0a992469e5cd0b3f7d1c249f9015 *data2 +8430fa32c8686a0d6a62769affdf454fc8429eacfbaf1eced94d95ecc1efef938616501103e58e7bd2371553c60e12ac274eac537efd0fbd6171f73536bc9a61 *data3 +c5d36b0ab741961fcfd8fc4250cb642905a5c5bb3649f5ace664a1b0bd57efd77626e8a7252c1499c71a05c54a0cf548acbc051c2a89cd490a242cd4963e7885 *data4 diff --git a/test/testdata/testcrlf.b2 b/test/testdata/testcrlf.b2 new file mode 100644 index 0000000..810ca24 --- /dev/null +++ b/test/testdata/testcrlf.b2 @@ -0,0 +1,4 @@ +5c5ce11923c07698f54cf30196efb3b038b44a77046fbabbdf3f2c2a924e10081e5f79cb4cd562f5590dc917c67fc0cdfaec0a992469e5cd0b3f7d1c249f9015 *data1 +5c5ce11923c07698f54cf30196efb3b038b44a77046fbabbdf3f2c2a924e10081e5f79cb4cd562f5590dc917c67fc0cdfaec0a992469e5cd0b3f7d1c249f9015 *data2 +8430fa32c8686a0d6a62769affdf454fc8429eacfbaf1eced94d95ecc1efef938616501103e58e7bd2371553c60e12ac274eac537efd0fbd6171f73536bc9a61 *data3 +c5d36b0ab741961fcfd8fc4250cb642905a5c5bb3649f5ace664a1b0bd57efd77626e8a7252c1499c71a05c54a0cf548acbc051c2a89cd490a242cd4963e7885 *data4