Een controlegetal (Engels: checksum) is een getal dat berekend wordt op basis van de inhoud van een bestand, met als doel om te controleren of het bestand niet beschadigd is tijdens het overbrengen van de ene computer naar de andere. Dataoverdracht is namelijk nooit perfect: zelfs onze moderne internetinfrastructuur kan niet garanderen dat er tijdens de overdracht van grote bestanden geen enkele fout zal optreden.

Checksums zijn dus een eenvoudige techniek om te detecteren of er fouten zijn opgetreden: je berekent een getal op basis van de inhoud van het bestand en je vergelijkt dat getal met de verwachte uitkomst die je van tevoren hebt gekregen. Als die twee getallen niet overeenkomen, dan is er iets fout gegaan tijdens de overdracht en moet je het bestand opnieuw downloaden. Een veelgebruikte checksum is SHA-2561. Op de command line kan je die als volgt berekenen:

$ sha256sum test.txt
cfc0468d0d29d24324bc3cbe05b54cbecf4b868278e3eb2c45c1a9f2ffbe5e22  test.txt

Dit geeft de SHA-256 checksum van het bestand test.txt2 in hexadecimale voorstelling. Probeer gerust zelf eens het bestand te downloaden en er dan de checksum van te berekenen. Je zou hetzelfde resultaat moeten krijgen als de checksum die in het voorbeeld hierboven staat.

De SHA-256 checksum wordt bijvoorbeeld gebruikt door Canonical3 om de integriteit van de Ubuntu-installatiebestanden te controleren (cf. handleiding van Ubuntu4). Ze combineren dit nog met digitale handtekeningen via GPG5 om te voorkomen dat checksums zelf vervalst kunnen worden. Digitale handtekeningen laten we voor deze opgave echter buiten beschouwing.

Opgave

Gegeven is een directorystructuur (ZIP6) waarin sommige bestanden ook een overeenkomstig checksum-bestand hebben. Zo'n checksum-bestand is een tekstbestand met dezelfde naam als het bestand waarvan de checksum berekend werd, aangevuld met de extensie .checksum. Het checksum-bestand staat in dezelfde directory als het bestand waarvan de checksum berekend werd. De inhoud van het bestand is de uitvoer (op stdout) van het commando sha256sum waarmee de checksum berekend werd.

Geef een Unix-commando dat in de huidige directory en alle onderliggende directories zoekt naar alle bestanden die een corresponderende checksum-bestand hebben en voor die bestanden te controleert of hun berekende checksum correspondeert met de checksum uit het checksum-bestand. Er zal immers telkens één bestand zijn waarvoor deze checksums niet corresponderen. Voor dit bestand moet het commando de relatieve padnaam ten opzichte van de huidige directory uitschrijven naar stdout.

Beschouw bijvoorbeeld de directory test1 waarvan een deel van de directorystructuur er als volgt uitziet:

test1
…
├── especially
│   └── serious
│       ├── cost.mp3
│       └── cost.mp3.checksum
…

Het bestand ./especially/serious/cost.mp3 heeft een checksum-bestand cost.mp3.checksum in dezelfde directory. Als we de berekende checksum van dit bestand vergelijken met de checksum uit het checksum-bestand, dan krijgen we:

$ cat ./especially/serious/cost.mp3.checksum 
b90a942abd7686ac8b66cb9d62d13e44e98594d0ccb5ce65aaf90bc91b0c1e2a  ./especially/serious/cost.mp3
$ sha256sum ./especially/serious/cost.mp3
7680e24be08e2960de1c988427821350b682d61c81d3c6c1ab588b6f4bfa6733  ./especially/serious/cost.mp3

Deze checksums komen niet overeen, dus moet in dit geval de padnaam ./especially/serious/cost.mp3 naar stdout uitgeschreven worden.

Tip

Deze oefening wordt bij voorkeur met een one-liner opgelost. Als je daar niet in slaagt, dan kan je een oplossing zoeken die bestaat uit meerdere commando's en tussentijdse resultaten eventueel ook uitschrijft naar tijdelijke bestanden. Als je tijdelijke bestanden aanmaakt, doe dit dan wel volgens de regels van de kunst7.