Repository: borgbackup/borg

Issue:
1.2.0 crashes when calculating statistics with older archives containing %
<!--
Thank you for reporting an issue.

*IMPORTANT* -  *before* creating a new issue please look around:
 - Borgbackup documentation: http://borgbackup.readthedocs.io/en/stable/index.html
 - FAQ: https://borgbackup.readthedocs.io/en/stable/faq.html
 and
 - open issues in Github tracker: https://github.com/borgbackup/borg/issues
  
If you cannot find a similar problem, then create a new issue.

Please fill in as much of the template as possible.
-->

## Have you checked borgbackup docs, FAQ, and open Github issues?

Yes, error from #6063 looks similar, though this was in the filename instead of the archive name and affected an older version.

## Is this a BUG / ISSUE report or a QUESTION?

BUG

## System information

```
Platform: Linux pc-arch 5.16.16-arch1-1 #1 SMP PREEMPT Mon, 21 Mar 2022 22:59:40 +0000 x86_64
Linux: Arch Linux  
Borg: 1.2.0  Python: CPython 3.10.3 msgpack: 1.0.3 fuse: llfuse 1.4.1 [pyfuse3,llfuse]
PID: 112950  CWD: /mnt/backup/BorgRepos
sys.argv: ['/usr/bin/borg', 'info', 'Laptop::Home_t440s-22.085']
SSH_ORIGINAL_COMMAND: None
```


## Describe the problem you're observing.
I created a new archive on this 5 years old repo, the first time with borg 1.2.0. It ran as usual, but failed at the end to get the statistics:
```
$ borg create -svp -C lz4 --patterns- .... 'Laptop::Home_t440s-{now:%y.%j}' $SRC

Local Exception
Traceback (most recent call last):
  File "/usr/lib/python3.10/site-packages/borg/archive.py", line 654, in calc_stats
    stats = Statistics.from_raw_dict(**cache.pre12_meta[self.fpr])
KeyError: '956cea6445100d48399f29e530cb1a994b86de3fcdb3978aa595e0dbadb93f52'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib/python3.10/site-packages/borg/archiver.py", line 5089, in main
    exit_code = archiver.run(args)
  File "/usr/lib/python3.10/site-packages/borg/archiver.py", line 5020, in run
    return set_ec(func(args))
  File "/usr/lib/python3.10/site-packages/borg/archiver.py", line 181, in wrapper
    return method(self, args, repository=repository, cache=cache_, **kwargs)
  File "/usr/lib/python3.10/site-packages/borg/archiver.py", line 1392, in do_info
    return self._info_archives(args, repository, manifest, key, cache)
  File "/usr/lib/python3.10/site-packages/borg/archiver.py", line 1417, in _info_archives
    print(textwrap.dedent("""
  File "/usr/lib/python3.10/site-packages/borg/cache.py", line 414, in __str__
    return self.str_format.format(self.format_tuple())
  File "/usr/lib/python3.10/site-packages/borg/cache.py", line 441, in format_tuple
    stats = self.stats()
  File "/usr/lib/python3.10/site-packages/borg/cache.py", line 433, in stats
    stats = archive.calc_stats(self, want_unique=False)
  File "/usr/lib/python3.10/site-packages/borg/archive.py", line 656, in calc_stats
    stats = self._calc_stats(cache, want_unique=want_unique)
  File "/usr/lib/python3.10/site-packages/borg/archive.py", line 678, in _calc_stats
    pi.show(increase=1)
  File "/usr/lib/python3.10/site-packages/borg/helpers/progress.py", line 157, in show
    return self.output(self.msg % pct)
ValueError: unsupported format character 'y' (0x79) at index 45
```
Also checking with:
```
borg info Laptop::Home_t440s-22.085
```
fails with the same exception. Actually it fails for every archive in that repo. 
So I looked into the repo and compared it with others that did not have this problem. Difference is one previous archive that has a `%` in the name.
Borg 1.1.7 (and below) never had a problem with it.
#### Can you reproduce the problem?
Yes, start with 1.1.7 or older:
```sh
borg init repo/ -e repokey
borg create -svp 'repo::good-name' test/
borg create -svp 'repo::bad-%-name' test/
borg info repo::good-name # WORKS
```
Then update to 1.2.0, while keeping the same repo:
```sh
borg info repo::good-name # FAILS
...
ValueError: unsupported format character 'n' (0x6e) at index 41
```
Workaround:
```sh
borg rename repo::bad-%-name less-bad-name
borg info repo::good-name # works again
```

Bounty: https://app.bountysource.com/issues/106415617-1-2-0-crashes-when-calculating-statistics-with-older-archives-containing



Discussion:
Yeah, that looks like a bug, thanks for reporting it!

Resolving patch:
diff --git a/src/borg/archive.py b/src/borg/archive.py
--- a/src/borg/archive.py
+++ b/src/borg/archive.py
@@ -671,8 +671,10 @@ def add(id):
             archive_index = ChunkIndex()
             sync = CacheSynchronizer(archive_index)
             add(self.id)
+            # we must escape any % char in the archive name, because we use it in a format string, see #6500
+            arch_name_escd = self.name.replace('%', '%%')
             pi = ProgressIndicatorPercent(total=len(self.metadata.items),
-                                          msg='Calculating statistics for archive %s ... %%3d%%%%' % self.name,
+                                          msg='Calculating statistics for archive %s ... %%3.0f%%%%' % arch_name_escd,
                                           msgid='archive.calc_stats')
             for id, chunk in zip(self.metadata.items, self.repository.get_many(self.metadata.items)):
                 pi.show(increase=1)


Test patch: