jborg/attic

ValueError on attic check --repair

jscinoz opened this issue · 4 comments

Similar to #232, I also encounter a crash on running check --repair. However, as the error is completely different, I figured it was more appropriate to log this as a separate issue. For the record, this crash occurs with Attic 0.16.

I'm attempting to run a check on what I believe to be a slightly damaged repository. The check runs for several hours, before crashing with the following error:

attic: Warning: 'check --repair' is an experimental feature that might result
in data loss.

Type "Yes I am sure" if you understand this and want to continue.

Do you want to continue? Yes I am sure
Starting repository check...
Traceback (most recent call last):
  File "/usr/bin/attic", line 3, in <module>
    main()
  File "/usr/lib64/python3.4/site-packages/attic/archiver.py", line 730, in main
    exit_code = archiver.run(sys.argv[1:])
  File "/usr/lib64/python3.4/site-packages/attic/archiver.py", line 720, in run
    return args.func(args)
  File "/usr/lib64/python3.4/site-packages/attic/archiver.py", line 81, in do_check
    if repository.check(repair=args.repair):
  File "/usr/lib64/python3.4/site-packages/attic/repository.py", line 268, in check
    objects = list(self.io.iter_objects(segment))
  File "/usr/lib64/python3.4/site-packages/attic/repository.py", line 500, in iter_objects
    rest = fd.read(size - self.header_fmt.size)
ValueError: read length must be positive or -1

Is there some way to work around this (removing an individual corrupted object/archive), or is my repository essentially gone at this point?

Looks like there is an invalid segment entry header (that usually contains a 32bit crc, a 32bit total entry size [header size + data size] and a 8bit tag).

As size - self.header_fmt.size obviously got negative here, size is obviously invalid.
Maybe it read 00 00 00 00 or FF FF FF FF for the 4 header bytes.

The size check in repository.py line 498 needs to get fixed to make it raise a documented/appropriate exception:

            if size > MAX_OBJECT_SIZE or size < self.header_fmt.size:

That will trigger the IntegrityError exception handler in check() and it will try to recover the segment.
Try if that helps.

Thanks @ThomasWaldmann I'll made the change and just started a check --repair. As the error doesn't show up until several hours in, I'll have to get back to you later on as to the outcome.

@ThomasWaldmann I can confirm that the check --repair now completes successfully with your amendment to repository.py