/*
 * zerogen.c (DFly UFS1) - zero di_gen of free inodes on an unmounted image,
 * simulating the legacy zero-gen condition under which ffs_valloc draws
 * krandom()/2+1 (ffs_alloc.c:641-642, ffs_vfsops.c:1174-1175).
 * usage: zerogen <image> <ino> [<ino>...]
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <fcntl.h>
#include <unistd.h>
#include <inttypes.h>
#include <sys/types.h>
#include <sys/endian.h>
#define MAXFRAG 8
#include "inc/ufs/ufs_types.h"
#include "inc/ufs/fs.h"
#include "inc/ufs/dinode.h"

#define SBLOCK_OFF 8192

int main(int argc, char **argv)
{
    if (argc < 3) { fprintf(stderr, "usage: zerogen image ino...\n"); return 2; }
    int fd = open(argv[1], O_RDWR);
    if (fd < 0) { perror("open"); return 1; }

    static char sbbuf[8192];
    if (pread(fd, sbbuf, sizeof(sbbuf), SBLOCK_OFF) != (ssize_t)sizeof(sbbuf)) {
        perror("pread sb"); return 1;
    }
    struct fs *fs = (struct fs *)sbbuf;
    uint32_t magic = le32toh(*(uint32_t *)&fs->fs_magic);
    /* fs fields on disk are little-endian on x86_64; magic compare directly */
    if (fs->fs_magic != FS_MAGIC && bswap32(fs->fs_magic) != FS_MAGIC) {
        fprintf(stderr, "bad fs magic 0x%x\n", (unsigned)fs->fs_magic);
        return 1;
    }
    int swapped = (fs->fs_magic != FS_MAGIC);
    (void)swapped; (void)magic;
    printf("sb ok: bsize=%d fsize=%d ipg=%d inopb=%d iblkno=%d cgoffset=%d\n",
           fs->fs_bsize, fs->fs_fsize, fs->fs_ipg, fs->fs_inopb,
           fs->fs_iblkno, fs->fs_cgoffset);

    for (int i = 2; i < argc; i++) {
        uint32_t ino = strtoul(argv[i], NULL, 0);
        off_t base = (off_t)ino_to_fsba(fs, ino) * (off_t)fs->fs_fsize;
        off_t ioff = base + (off_t)ino_to_fsbo(fs, ino) * (off_t)sizeof(struct ufs1_dinode);
        off_t goff = ioff + (off_t)offsetof(struct ufs1_dinode, di_gen);
        uint32_t gen;
        if (pread(fd, &gen, 4, goff) != 4) { perror("pread gen"); return 1; }
        printf("ino %u: dinode@%lld di_gen@%lld = 0x%08x -> 0\n",
               ino, (long long)ioff, (long long)goff, (unsigned)gen);
        if (getenv("ZG_PRINT") == NULL) {
            uint32_t z = 0;
            if (pwrite(fd, &z, 4, goff) != 4) { perror("pwrite gen"); return 1; }
        }
    }
    fsync(fd);
    close(fd);
    printf("done\n");
    return 0;
}
