// scrub.c — checksums por bloque guardados aparte, y un "scrubber" que los verifica.
//
// Uso: ./scrub sign  ARCHIVO   calcula un CRC-32 por bloque de 4 KiB y lo guarda
//                              en ARCHIVO.sum (como haría el sistema de archivos)
//      ./scrub check ARCHIVO   relee todo el archivo y compara bloque por bloque
//
// El checksum va en un archivo aparte, no junto a cada bloque: así una escritura
// perdida o mal dirigida no se lleva el dato y su checksum a la vez.
#include <stdint.h>
#include <stdio.h>
#include <string.h>

#define BLK 4096

static uint32_t crc32(const uint8_t *d, size_t n) {
    uint32_t c = 0xFFFFFFFFu;
    for (size_t i = 0; i < n; i++) {
        c ^= d[i];
        for (int k = 0; k < 8; k++)
            c = (c >> 1) ^ (0xEDB88320u & -(c & 1));
    }
    return ~c;
}

int main(int argc, char *argv[]) {
    if (argc != 3 || (strcmp(argv[1], "sign") && strcmp(argv[1], "check"))) {
        fprintf(stderr, "uso: %s sign|check ARCHIVO\n", argv[0]);
        return 2;
    }
    int sign = strcmp(argv[1], "sign") == 0;
    char sumname[4096];
    snprintf(sumname, sizeof(sumname), "%s.sum", argv[2]);

    FILE *f = fopen(argv[2], "rb");
    FILE *s = fopen(sumname, sign ? "wb" : "rb");
    if (!f || !s) {
        perror(!f ? argv[2] : sumname);
        return 2;
    }

    uint8_t buf[BLK];
    size_t n, blk = 0;
    int bad = 0;
    while ((n = fread(buf, 1, BLK, f)) > 0) {
        uint32_t now = crc32(buf, n);
        if (sign) {
            fwrite(&now, sizeof(now), 1, s);
        } else {
            uint32_t saved;
            if (fread(&saved, sizeof(saved), 1, s) != 1) {
                printf("bloque %zu: no hay checksum guardado\n", blk);
                bad++;
            } else if (saved != now) {
                printf("bloque %zu: CORRUPTO (guardado %08x, leído %08x)\n", blk, saved, now);
                bad++;
            }
        }
        blk++;
    }
    fclose(f);
    fclose(s);

    if (sign)
        printf("%zu bloques firmados en %s\n", blk, sumname);
    else
        printf("%zu bloques revisados, %d con errores\n", blk, bad);
    return bad ? 1 : 0;
}
