From 340ea657349edb244b549f19edca902beee18ee9 Mon Sep 17 00:00:00 2001 From: Mark Wooding Date: Wed, 7 Feb 2024 19:03:33 +0000 Subject: [PATCH] fshash.in, fshash.1: Don't reuse virtual inode numbers spuriously. There was code to prevent collisions this when generating new virtual inodes, but the code which was supposed to record which ones had been generated so far was missing. Of course, changing this breaks compatibility with old manifests, so we need a mechanism to support that. I wouldn't usually make two apparently unrelated changes like this in one commit: I'd, say, introduce the compatibility machinery first, and then fix the virtual-inode bug. But that won't work: one of the things compatibility version 2 should do is print a comment (so that you can tell that a mismatch is because of this setting), but that needs to arrive in the same change as the bug fix. Sorry. --- fshash.1 | 16 ++++++++++++++++ fshash.in | 29 ++++++++++++++++++----------- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/fshash.1 b/fshash.1 index 788a7d8..8577d65 100644 --- a/fshash.1 +++ b/fshash.1 @@ -12,6 +12,8 @@ .IR cache ] .RB [ \-f .IR format ] +.RB [ \-C +.IR version ] .RB [ \-H .IR hash ] .RI [ file @@ -95,6 +97,20 @@ format doesn't work well: see .B BUGS below.) .TP +.B \-C, \-\-compat=\fIversion +Produce a manifest with the given compatibility +.IR version . +Alas, +.B fshash +has bugs in the way it produces manifests. Fixing the bugs makes the +output better, but now it can't be compared with old manifests which +were made with the bugs. By default, +.B fshash +produces manifests in the most recent format, but this option will force +it to be compatible with old versions. The original version was 1; all +later versions print a comment reporting the version number at the start +of the manifest. The current version is 2. +.TP .B \-H, \-\-hash=\fIhash Use the .I hash diff --git a/fshash.in b/fshash.in index 525b0f0..dcfd229 100644 --- a/fshash.in +++ b/fshash.in @@ -449,6 +449,7 @@ class Reporter (object): suffix = '\0%d' % seq seq += 1 me._inomap[inoidx] = vino + if OPTS.compat >= 2: me._vinomap[vino] = inoidx if h: info = h else: info = '[%-*s]' % (2*me._hsz - 2, fmt.info()) print '%s %8s %6s %-12s %-20s %20s %s' % ( @@ -586,33 +587,39 @@ for short, long, props in [ 'help': 'read files to report in the given FORMAT' }), ('-u', '--udiff', { 'action': 'store_true', 'dest': 'udiff', 'help': 'read diff from stdin, clear cache entries' }), + ('-C', '--compat', { 'dest': 'compat', 'metavar': 'VERSION', + 'type': 'int', 'default': 2, + 'help': 'produce output with given compatibility VERSION' }), ('-H', '--hash', { 'dest': 'hash', 'metavar': 'HASH', ##'type': 'choice', 'choices': H.algorithms, 'help': 'use HASH as the hash function' })]: op.add_option(short, long, **props) -opts, args = op.parse_args(argv) - -if opts.udiff: - if opts.cache is None or opts.all or opts.files or len(args) > 2: +OPTS, args = op.parse_args(argv) +if not 1 <= OPTS.compat <= 2: + die("unknown compatibility version %d" % OPTS.compat) +if OPTS.udiff: + if OPTS.cache is None or OPTS.all or OPTS.files or len(args) > 2: die("incompatible options: `-u' requires `-c CACHE', forbids others") - db = HashCache(opts.cache, opts.hash) + db = HashCache(OPTS.cache, OPTS.hash) if len(args) == 2: OS.chdir(args[1]) good = True if not clear_cache(db): good = False if good: db.flush() else: exit(2) else: - if not opts.files and len(args) <= 1: + if not OPTS.files and len(args) <= 1: die("no filename sources: nothing to do") - db = HashCache(opts.cache, opts.hash) - if opts.all: + db = HashCache(OPTS.cache, OPTS.hash) + if OPTS.all: db.reset() + if OPTS.compat >= 2: + print "## fshash report format version %d" % OPTS.compat rep = Reporter(db) - if opts.files: - FMTMAP[opts.files](rep.file) + if OPTS.files: + FMTMAP[OPTS.files](rep.file) for dir in args[1:]: enum_walk(dir, rep.file) - if opts.all: + if OPTS.all: db.prune() db.flush() -- 2.11.0