/* inopatch.c — patch a ufs1 dinode field directly in a FFS image.
 * usage: inopatch <img> <ino> <size|uid|gid|mode> <value>
 * computes the inode's block via the fs.h macros (geometry read from sb).
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <sys/param.h>
#include <vfs/ufs/ufs_types.h>
#include <vfs/ufs/fs.h>
#include <vfs/ufs/dinode.h>

#define SBOFF 8192

int main(int argc, char **argv){
    if (argc < 5) { fprintf(stderr, "usage: inopatch img ino size|uid|mode val\n"); return 1; }
    FILE *f = fopen(argv[1], "r+b");
    if (!f) { perror("open"); return 1; }
    struct fs sb;
    fseek(f, SBOFF, SEEK_SET);
    if (fread(&sb, sizeof sb, 1, f) != 1) { perror("read sb"); return 1; }
    ino_t ino = strtoull(argv[2], NULL, 0);
    /* byte offset of the inode's fragment on the media */
    off_t fsboff = (off_t)ino_to_fsba(&sb, ino) * sb.fs_fsize
                 + (off_t)ino_to_fsbo(&sb, ino) * sizeof(struct ufs1_dinode);
    struct ufs1_dinode di;
    fseek(f, fsboff, SEEK_SET);
    if (fread(&di, sizeof di, 1, f) != 1) { perror("read inode"); return 1; }
    printf("ino %llu at media off %lld: mode=0%o nlink=%d size=%lld blocks=%lld "
           "ib=[%d,%d,%d] uid=%d\n",
        (unsigned long long)ino, (long long)fsboff, di.di_mode, di.di_nlink,
        (long long)di.di_size, (long long)di.di_blocks,
        (int)di.di_ib[0], (int)di.di_ib[1], (int)di.di_ib[2], di.di_uid);
    const char *fld = argv[3];
    if (!strcmp(fld, "size"))      di.di_size = strtoull(argv[4], NULL, 0);
    else if (!strcmp(fld, "uid"))  di.di_uid  = (int32_t)strtoul(argv[4], NULL, 0);
    else if (!strcmp(fld, "gid"))  di.di_gid  = (int32_t)strtoul(argv[4], NULL, 0);
    else if (!strcmp(fld, "mode")) di.di_mode = (uint16_t)strtoul(argv[4], NULL, 0);
    else { fprintf(stderr, "unknown field\n"); return 1; }
    fseek(f, fsboff, SEEK_SET);
    fwrite(&di, sizeof di, 1, f);
    printf("patched %s=%s\n", fld, argv[4]);
    fclose(f);
    return 0;
}
